blob: 81e793475bbb81d9e07fce1b4ba69a1fa1208c5a [file] [log] [blame]
willy tarreau0f7af912005-12-17 12:21:26 +01001/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01002 * HA-Proxy : High Availability-enabled HTTP/TCP proxy
willy tarreau726618c2006-01-29 22:42:06 +01003 * 2000-2006 - Willy Tarreau - willy AT meta-x DOT org.
willy tarreau0f7af912005-12-17 12:21:26 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
willy tarreau906b2682005-12-17 13:49:52 +010010 * Please refer to RFC2068 or RFC2616 for informations about HTTP protocol, and
willy tarreau982249e2005-12-18 00:57:06 +010011 * RFC2965 for informations about cookies usage. More generally, the IETF HTTP
12 * Working Group's web site should be consulted for protocol related changes :
13 *
14 * http://ftp.ics.uci.edu/pub/ietf/http/
willy tarreau906b2682005-12-17 13:49:52 +010015 *
16 * Pending bugs (may be not fixed because never reproduced) :
willy tarreaua1598082005-12-17 13:08:06 +010017 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
18 * the proxy to terminate (no core) if the client breaks the connection during
willy tarreauc29948c2005-12-17 13:10:27 +010019 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
willy tarreau8337c6b2005-12-17 13:41:01 +010020 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
21 * related to missing setsid() (fixed in 1.1.15)
willy tarreauef900ab2005-12-17 12:52:52 +010022 * - a proxy with an invalid config will prevent the startup even if disabled.
23 *
willy tarreau036e1ce2005-12-17 13:46:33 +010024 * ChangeLog has moved to the CHANGELOG file.
willy tarreau0f7af912005-12-17 12:21:26 +010025 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010026 * TODO:
27 * - handle properly intermediate incomplete server headers. Done ?
willy tarreau5cbea6f2005-12-17 12:48:26 +010028 * - handle hot-reconfiguration
willy tarreau906b2682005-12-17 13:49:52 +010029 * - fix client/server state transition when server is in connect or headers state
30 * and client suddenly disconnects. The server *should* switch to SHUT_WR, but
31 * still handle HTTP headers.
willy tarreau4302f492005-12-18 01:00:37 +010032 * - remove MAX_NEWHDR
willy tarreauc1f47532005-12-18 01:08:26 +010033 * - cut this huge file into several ones
willy tarreau0f7af912005-12-17 12:21:26 +010034 *
35 */
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <unistd.h>
40#include <string.h>
41#include <ctype.h>
42#include <sys/time.h>
43#include <sys/types.h>
44#include <sys/socket.h>
45#include <netinet/tcp.h>
46#include <netinet/in.h>
47#include <arpa/inet.h>
48#include <netdb.h>
49#include <fcntl.h>
50#include <errno.h>
51#include <signal.h>
52#include <stdarg.h>
53#include <sys/resource.h>
54#include <time.h>
willy tarreau0f7af912005-12-17 12:21:26 +010055#include <syslog.h>
willy tarreau77bc8542005-12-18 01:31:43 +010056
57#ifdef USE_PCRE
58#include <pcre.h>
59#include <pcreposix.h>
60#else
61#include <regex.h>
62#endif
63
willy tarreaua1598082005-12-17 13:08:06 +010064#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +010065#include <linux/netfilter_ipv4.h>
66#endif
willy tarreau0f7af912005-12-17 12:21:26 +010067
willy tarreau12350152005-12-18 01:03:27 +010068#if defined(__dietlibc__)
69#include <strings.h>
70#endif
71
willy tarreau1c2ad212005-12-18 01:11:29 +010072#if defined(ENABLE_POLL)
73#include <sys/poll.h>
74#endif
75
76#if defined(ENABLE_EPOLL)
77#if !defined(USE_MY_EPOLL)
willy tarreauad90a0c2005-12-18 01:09:15 +010078#include <sys/epoll.h>
willy tarreau1c2ad212005-12-18 01:11:29 +010079#else
80#include "include/epoll.h"
81#endif
82#endif
willy tarreauad90a0c2005-12-18 01:09:15 +010083
willy tarreau779dc892006-03-19 19:32:29 +010084#ifdef DEBUG_FULL
85#include <assert.h>
86#endif
87
willy tarreau598da412005-12-18 01:07:29 +010088#include "include/appsession.h"
willy tarreau12350152005-12-18 01:03:27 +010089
willy tarreaubfad5742006-03-23 14:19:11 +010090#ifndef HAPROXY_VERSION
willy tarreaue0dd2692006-03-30 16:27:34 +020091#define HAPROXY_VERSION "1.2.11.1"
willy tarreaubfad5742006-03-23 14:19:11 +010092#endif
93
94#ifndef HAPROXY_DATE
willy tarreaue0dd2692006-03-30 16:27:34 +020095#define HAPROXY_DATE "2006/03/30"
willy tarreaubfad5742006-03-23 14:19:11 +010096#endif
willy tarreau0f7af912005-12-17 12:21:26 +010097
98/* this is for libc5 for example */
99#ifndef TCP_NODELAY
100#define TCP_NODELAY 1
101#endif
102
103#ifndef SHUT_RD
104#define SHUT_RD 0
105#endif
106
107#ifndef SHUT_WR
108#define SHUT_WR 1
109#endif
110
willy tarreau0174f312005-12-18 01:02:42 +0100111/*
112 * BUFSIZE defines the size of a read and write buffer. It is the maximum
113 * amount of bytes which can be stored by the proxy for each session. However,
114 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
115 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
116 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
117 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
118 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
119 */
120#ifndef BUFSIZE
121#define BUFSIZE 16384
122#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100123
124// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100125#ifndef MAXREWRITE
126#define MAXREWRITE (BUFSIZE / 2)
127#endif
128
willy tarreau9fe663a2005-12-17 13:02:59 +0100129#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100130#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100131
willy tarreau5cbea6f2005-12-17 12:48:26 +0100132// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100133#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100134
willy tarreaue39cd132005-12-17 13:00:18 +0100135// max # of added headers per request
136#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100137
138// max # of matches per regexp
139#define MAX_MATCH 10
140
willy tarreau0174f312005-12-18 01:02:42 +0100141// cookie delimitor in "prefix" mode. This character is inserted between the
142// persistence cookie and the original value. The '~' is allowed by RFC2965,
143// and should not be too common in server names.
144#ifndef COOKIE_DELIM
145#define COOKIE_DELIM '~'
146#endif
147
willy tarreau0f7af912005-12-17 12:21:26 +0100148#define CONN_RETRIES 3
149
willy tarreau5cbea6f2005-12-17 12:48:26 +0100150#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100151#define DEF_CHKINTR 2000
152#define DEF_FALLTIME 3
153#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100154#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100155
Willy TARREAU13032e72006-03-12 17:31:45 +0100156/* Default connections limit.
157 *
158 * A system limit can be enforced at build time in order to avoid using haproxy
159 * beyond reasonable system limits. For this, just define SYSTEM_MAXCONN to the
160 * absolute limit accepted by the system. If the configuration specifies a
161 * higher value, it will be capped to SYSTEM_MAXCONN and a warning will be
162 * emitted. The only way to override this limit will be to set it via the
163 * command-line '-n' argument.
164 */
165#ifndef SYSTEM_MAXCONN
willy tarreau9fe663a2005-12-17 13:02:59 +0100166#define DEFAULT_MAXCONN 2000
Willy TARREAU13032e72006-03-12 17:31:45 +0100167#else
168#define DEFAULT_MAXCONN SYSTEM_MAXCONN
169#endif
willy tarreau9fe663a2005-12-17 13:02:59 +0100170
willy tarreau0f7af912005-12-17 12:21:26 +0100171/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
172#define INTBITS 5
173
174/* show stats this every millisecond, 0 to disable */
175#ifndef STATTIME
176#define STATTIME 2000
177#endif
178
willy tarreau5cbea6f2005-12-17 12:48:26 +0100179/* this reduces the number of calls to select() by choosing appropriate
180 * sheduler precision in milliseconds. It should be near the minimum
181 * time that is needed by select() to collect all events. All timeouts
182 * are rounded up by adding this value prior to pass it to select().
183 */
184#define SCHEDULER_RESOLUTION 9
185
willy tarreaub952e1d2005-12-18 01:31:20 +0100186#define TIME_ETERNITY -1
187/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100188#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
189#define SETNOW(a) (*a=now)
190
willy tarreau9da061b2005-12-17 12:29:56 +0100191/****** string-specific macros and functions ******/
192/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
193#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
194
195/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
196#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
197
willy tarreau0174f312005-12-18 01:02:42 +0100198/* returns 1 only if only zero or one bit is set in X, which means that X is a
199 * power of 2, and 0 otherwise */
200#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100201/*
202 * copies at most <size-1> chars from <src> to <dst>. Last char is always
203 * set to 0, unless <size> is 0. The number of chars copied is returned
204 * (excluding the terminating zero).
205 * This code has been optimized for size and speed : on x86, it's 45 bytes
206 * long, uses only registers, and consumes only 4 cycles per char.
207 */
willy tarreau750a4722005-12-17 13:21:24 +0100208int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100209 char *orig = dst;
210 if (size) {
211 while (--size && (*dst = *src)) {
212 src++; dst++;
213 }
214 *dst = 0;
215 }
216 return dst - orig;
217}
willy tarreau9da061b2005-12-17 12:29:56 +0100218
willy tarreau4302f492005-12-18 01:00:37 +0100219/*
220 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
221 * dynamically allocated. In the first case, <__pool> is updated to point to
222 * the next element in the list.
223 */
224#define pool_alloc_from(__pool, __len) ({ \
225 void *__p; \
226 if ((__p = (__pool)) == NULL) \
227 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
228 else { \
229 __pool = *(void **)(__pool); \
230 } \
231 __p; \
232})
233
234/*
235 * Puts a memory area back to the corresponding pool.
236 * Items are chained directly through a pointer that
237 * is written in the beginning of the memory area, so
238 * there's no need for any carrier cell. This implies
239 * that each memory area is at least as big as one
240 * pointer.
241 */
242#define pool_free_to(__pool, __ptr) ({ \
243 *(void **)(__ptr) = (void *)(__pool); \
244 __pool = (void *)(__ptr); \
245})
246
247
willy tarreau0f7af912005-12-17 12:21:26 +0100248#define MEM_OPTIM
249#ifdef MEM_OPTIM
250/*
251 * Returns a pointer to type <type> taken from the
252 * pool <pool_type> or dynamically allocated. In the
253 * first case, <pool_type> is updated to point to the
254 * next element in the list.
255 */
256#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100257 void *__p; \
258 if ((__p = pool_##type) == NULL) \
259 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100260 else { \
261 pool_##type = *(void **)pool_##type; \
262 } \
willy tarreau4302f492005-12-18 01:00:37 +0100263 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100264})
265
266/*
267 * Puts a memory area back to the corresponding pool.
268 * Items are chained directly through a pointer that
269 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100270 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100271 * that each memory area is at least as big as one
272 * pointer.
273 */
274#define pool_free(type, ptr) ({ \
275 *(void **)ptr = (void *)pool_##type; \
276 pool_##type = (void *)ptr; \
277})
278
279#else
280#define pool_alloc(type) (calloc(1,sizeof_##type));
281#define pool_free(type, ptr) (free(ptr));
282#endif /* MEM_OPTIM */
283
willy tarreau5cbea6f2005-12-17 12:48:26 +0100284#define sizeof_task sizeof(struct task)
285#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100286#define sizeof_buffer sizeof(struct buffer)
287#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100288#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100289#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100290#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100291#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100292
willy tarreau5cbea6f2005-12-17 12:48:26 +0100293/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100294#define FD_STCLOSE 0
295#define FD_STLISTEN 1
296#define FD_STCONN 2
297#define FD_STREADY 3
298#define FD_STERROR 4
299
willy tarreau5cbea6f2005-12-17 12:48:26 +0100300/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100301#define TASK_IDLE 0
302#define TASK_RUNNING 1
303
willy tarreau5cbea6f2005-12-17 12:48:26 +0100304/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100305#define PR_STNEW 0
306#define PR_STIDLE 1
307#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100308#define PR_STSTOPPED 3
309#define PR_STPAUSED 4
willy tarreau0f7af912005-12-17 12:21:26 +0100310
willy tarreau5cbea6f2005-12-17 12:48:26 +0100311/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100312#define PR_MODE_TCP 0
313#define PR_MODE_HTTP 1
314#define PR_MODE_HEALTH 2
315
willy tarreau1c2ad212005-12-18 01:11:29 +0100316/* possible actions for the *poll() loops */
317#define POLL_LOOP_ACTION_INIT 0
318#define POLL_LOOP_ACTION_RUN 1
319#define POLL_LOOP_ACTION_CLEAN 2
320
willy tarreau64a3cc32005-12-18 01:13:11 +0100321/* poll mechanisms available */
322#define POLL_USE_SELECT (1<<0)
323#define POLL_USE_POLL (1<<1)
324#define POLL_USE_EPOLL (1<<2)
325
willy tarreau5cbea6f2005-12-17 12:48:26 +0100326/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100327#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
328#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
329#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
330#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
331#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
332#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
333#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
334#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau0174f312005-12-18 01:02:42 +0100335#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
336#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
337#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
338#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
339#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
340#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
341#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
342#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
343#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
344#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
345#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100346#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
347#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100348#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100349#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau1a3442d2006-03-24 21:03:20 +0100350#define PR_O_BALANCE_SH 0x00400000 /* balance on source IP hash */
351#define PR_O_BALANCE (PR_O_BALANCE_RR | PR_O_BALANCE_SH)
willy tarreau5cbea6f2005-12-17 12:48:26 +0100352
willy tarreaue39cd132005-12-17 13:00:18 +0100353/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100354#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
355#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
356#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
357#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
358#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
359#define SN_POST 0x00000020 /* the request was an HTTP POST */
willy tarreaub1285d52005-12-18 01:20:14 +0100360#define SN_MONITOR 0x00000040 /* this session comes from a monitoring system */
willy tarreau036e1ce2005-12-17 13:46:33 +0100361
362#define SN_CK_NONE 0x00000000 /* this session had no cookie */
363#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
364#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
365#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
366#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
367#define SN_CK_SHIFT 6 /* bit shift */
368
willy tarreaub1285d52005-12-18 01:20:14 +0100369#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100370#define SN_ERR_CLITO 0x00000100 /* client time-out */
371#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
372#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
373#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
374#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100375#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
376#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100377#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
378#define SN_ERR_SHIFT 8 /* bit shift */
379
380#define SN_FINST_R 0x00001000 /* session ended during client request */
381#define SN_FINST_C 0x00002000 /* session ended during server connect */
382#define SN_FINST_H 0x00003000 /* session ended during server headers */
383#define SN_FINST_D 0x00004000 /* session ended during data phase */
384#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
385#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
386#define SN_FINST_SHIFT 12 /* bit shift */
387
388#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
389#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
390#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
391#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
392#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100393#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100394#define SN_SCK_SHIFT 16 /* bit shift */
395
willy tarreau97f58572005-12-18 00:53:44 +0100396#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
397#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
398#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100399
400/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100401#define CL_STHEADERS 0
402#define CL_STDATA 1
403#define CL_STSHUTR 2
404#define CL_STSHUTW 3
405#define CL_STCLOSE 4
406
willy tarreau5cbea6f2005-12-17 12:48:26 +0100407/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100408#define SV_STIDLE 0
409#define SV_STCONN 1
410#define SV_STHEADERS 2
411#define SV_STDATA 3
412#define SV_STSHUTR 4
413#define SV_STSHUTW 5
414#define SV_STCLOSE 6
415
416/* result of an I/O event */
417#define RES_SILENT 0 /* didn't happen */
418#define RES_DATA 1 /* data were sent or received */
419#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
420#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
421
willy tarreau9fe663a2005-12-17 13:02:59 +0100422/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100423#define MODE_DEBUG 1
424#define MODE_STATS 2
425#define MODE_LOG 4
426#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100427#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100428#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100429#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100430#define MODE_STARTING 128
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100431#define MODE_FOREGROUND 256
willy tarreau5cbea6f2005-12-17 12:48:26 +0100432
433/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100434#define SRV_RUNNING 1 /* the server is UP */
435#define SRV_BACKUP 2 /* this server is a backup server */
436#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100437#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100438#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100439
willy tarreaue39cd132005-12-17 13:00:18 +0100440/* what to do when a header matches a regex */
441#define ACT_ALLOW 0 /* allow the request */
442#define ACT_REPLACE 1 /* replace the matching header */
443#define ACT_REMOVE 2 /* remove the matching header */
444#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100445#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100446
willy tarreau9fe663a2005-12-17 13:02:59 +0100447/* configuration sections */
448#define CFG_NONE 0
449#define CFG_GLOBAL 1
450#define CFG_LISTEN 2
451
willy tarreaua1598082005-12-17 13:08:06 +0100452/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100453#define LW_DATE 1 /* date */
454#define LW_CLIP 2 /* CLient IP */
455#define LW_SVIP 4 /* SerVer IP */
456#define LW_SVID 8 /* server ID */
457#define LW_REQ 16 /* http REQuest */
458#define LW_RESP 32 /* http RESPonse */
459#define LW_PXIP 64 /* proxy IP */
460#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100461#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100462#define LW_COOKIE 512 /* captured cookie */
463#define LW_REQHDR 1024 /* request header(s) */
464#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100465
willy tarreau41310e72006-03-25 18:17:56 +0100466#define ERR_NONE 0 /* no error */
467#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
468#define ERR_FATAL 2 /* fatal error, may be cumulated */
469
willy tarreau0f7af912005-12-17 12:21:26 +0100470/*********************************************************************/
471
472#define LIST_HEAD(a) ((void *)(&(a)))
473
474/*********************************************************************/
475
willy tarreau4302f492005-12-18 01:00:37 +0100476struct cap_hdr {
477 struct cap_hdr *next;
478 char *name; /* header name, case insensitive */
479 int namelen; /* length of the header name, to speed-up lookups */
480 int len; /* capture length, not including terminal zero */
481 int index; /* index in the output array */
482 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
483};
484
willy tarreau0f7af912005-12-17 12:21:26 +0100485struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100486 struct hdr_exp *next;
487 regex_t *preg; /* expression to look for */
488 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
489 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100490};
491
492struct buffer {
493 unsigned int l; /* data length */
494 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100495 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100496 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100497 char data[BUFSIZE];
498};
499
500struct server {
501 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100502 int state; /* server state (SRV_*) */
503 int cklen; /* the len of the cookie, to speed up checks */
504 char *cookie; /* the id set in the cookie */
505 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100506 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100507 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100508 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100509 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100510 int rise, fall; /* time in iterations */
511 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100512 int result; /* 0 = connect OK, -1 = connect KO */
513 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreauc1364612006-04-07 16:28:28 +0200514 int cur_sess; /* number of currently active sessions (including syn_sent) */
515 unsigned int cum_sess; /* cumulated number of sessions really sent to this server */
willy tarreau3b002c72006-04-08 21:52:24 +0200516 unsigned char uweight, eweight; /* user-specified weight-1, and effective weight-1 */
517 unsigned short wsquare; /* eweight*eweight, to speed up map computation */
willy tarreau535ae7a2005-12-17 12:58:00 +0100518 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100519};
520
willy tarreau5cbea6f2005-12-17 12:48:26 +0100521/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100522struct task {
523 struct task *next, *prev; /* chaining ... */
524 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100525 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100526 int state; /* task state : IDLE or RUNNING */
527 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100528 int (*process)(struct task *t); /* the function which processes the task */
529 void *context; /* the task's context */
530};
531
532/* WARNING: if new fields are added, they must be initialized in event_accept() */
533struct session {
534 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100535 /* application specific below */
536 struct timeval crexpire; /* expiration date for a client read */
537 struct timeval cwexpire; /* expiration date for a client write */
538 struct timeval srexpire; /* expiration date for a server read */
539 struct timeval swexpire; /* expiration date for a server write */
540 struct timeval cnexpire; /* expiration date for a connect */
541 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
542 struct proxy *proxy; /* the proxy this socket belongs to */
543 int cli_fd; /* the client side fd */
544 int srv_fd; /* the server side fd */
545 int cli_state; /* state of the client side */
546 int srv_state; /* state of the server side */
547 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100548 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100549 struct buffer *req; /* request buffer */
550 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100551 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100552 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100553 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100554 char **req_cap; /* array of captured request headers (may be NULL) */
555 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100556 struct {
557 int logwait; /* log fields waiting to be collected : LW_* */
558 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
559 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
560 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
561 long t_data; /* delay before the first data byte from the server ... */
562 unsigned long t_close; /* total session duration */
563 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100564 char *cli_cookie; /* cookie presented by the client, in capture mode */
565 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100566 int status; /* HTTP status from the server, negative if from proxy */
567 long long bytes; /* number of bytes transferred from the server */
568 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100569 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100570};
571
willy tarreaua41a8b42005-12-17 14:02:24 +0100572struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100573 int fd; /* the listen socket */
574 struct sockaddr_storage addr; /* the address we listen to */
575 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100576};
577
578
willy tarreau0f7af912005-12-17 12:21:26 +0100579struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100580 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100581 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 +0100582 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100583 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100584 struct server *srv, *cursrv; /* known servers, current server */
willy tarreau62084d42006-03-24 18:57:41 +0100585 int srv_act, srv_bck; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100586 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100587 int cookie_len; /* strlen(cookie_name), computed only once */
588 char *appsession_name; /* name of the cookie to look for */
589 int appsession_name_len; /* strlen(appsession_name), computed only once */
590 int appsession_len; /* length of the appsession cookie value to be used */
591 int appsession_timeout;
592 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100593 char *capture_name; /* beginning of the name of the cookie to capture */
594 int capture_namelen; /* length of the cookie name to match */
595 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100596 int clitimeout; /* client I/O timeout (in milliseconds) */
597 int srvtimeout; /* server I/O timeout (in milliseconds) */
598 int contimeout; /* connect timeout (in milliseconds) */
599 char *id; /* proxy id */
600 int nbconn; /* # of active sessions */
willy tarreaub1c331f2006-04-07 18:23:29 +0200601 unsigned int cum_conn; /* cumulated number of processed sessions */
willy tarreau0f7af912005-12-17 12:21:26 +0100602 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100603 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100604 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100605 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100606 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100607 struct proxy *next;
608 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100609 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100610 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100611 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100612 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100613 int nb_reqadd, nb_rspadd;
614 struct hdr_exp *req_exp; /* regular expressions for request headers */
615 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100616 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
617 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
618 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
619 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100620 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100621 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100622 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
623 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100624 struct {
625 char *msg400; /* message for error 400 */
626 int len400; /* message length for error 400 */
627 char *msg403; /* message for error 403 */
628 int len403; /* message length for error 403 */
629 char *msg408; /* message for error 408 */
630 int len408; /* message length for error 408 */
631 char *msg500; /* message for error 500 */
632 int len500; /* message length for error 500 */
633 char *msg502; /* message for error 502 */
634 int len502; /* message length for error 502 */
635 char *msg503; /* message for error 503 */
636 int len503; /* message length for error 503 */
637 char *msg504; /* message for error 504 */
638 int len504; /* message length for error 504 */
639 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100640};
641
642/* info about one given fd */
643struct fdtab {
644 int (*read)(int fd); /* read function */
645 int (*write)(int fd); /* write function */
646 struct task *owner; /* the session (or proxy) associated with this fd */
647 int state; /* the state of this fd */
648};
649
650/*********************************************************************/
651
willy tarreaub952e1d2005-12-18 01:31:20 +0100652int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100653int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100654char *cfg_cfgfile = NULL; /* configuration file */
655char *progname = NULL; /* program name */
656int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100657
658/* global options */
659static struct {
660 int uid;
661 int gid;
662 int nbproc;
663 int maxconn;
664 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100665 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100666 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100667 int mode;
668 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100669 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100670 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100671 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100672 struct sockaddr_in logsrv1, logsrv2;
673} global = {
674 logfac1 : -1,
675 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100676 loglev1 : 7, /* max syslog level : debug */
677 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100678 /* others NULL OK */
679};
680
willy tarreau0f7af912005-12-17 12:21:26 +0100681/*********************************************************************/
682
willy tarreau1c2ad212005-12-18 01:11:29 +0100683fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100684 *StaticWriteEvent;
685
willy tarreau64a3cc32005-12-18 01:13:11 +0100686int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100687
willy tarreau0f7af912005-12-17 12:21:26 +0100688void **pool_session = NULL,
689 **pool_buffer = NULL,
690 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100691 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100692 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100693 **pool_capture = NULL,
694 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100695
696struct proxy *proxy = NULL; /* list of all existing proxies */
697struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100698struct task *rq = NULL; /* global run queue */
699struct task wait_queue = { /* global wait queue */
700 prev:LIST_HEAD(wait_queue),
701 next:LIST_HEAD(wait_queue)
702};
willy tarreau0f7af912005-12-17 12:21:26 +0100703
willy tarreau0f7af912005-12-17 12:21:26 +0100704static int totalconn = 0; /* total # of terminated sessions */
705static int actconn = 0; /* # of active sessions */
706static int maxfd = 0; /* # of the highest fd + 1 */
707static int listeners = 0; /* # of listeners */
708static int stopping = 0; /* non zero means stopping in progress */
709static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100710static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100711
willy tarreau53e99702006-03-25 18:53:50 +0100712/* Here we store informations about the pids of the processes we may pause
713 * or kill. We will send them a signal every 10 ms until we can bind to all
714 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100715 */
willy tarreau53e99702006-03-25 18:53:50 +0100716#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100717static int nb_oldpids = 0;
718static int *oldpids = NULL;
719static int oldpids_sig; /* use USR1 or TERM */
720
willy tarreau08dedbe2005-12-18 01:13:48 +0100721#if defined(ENABLE_EPOLL)
722/* FIXME: this is dirty, but at the moment, there's no other solution to remove
723 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
724 * structure with pointers to functions such as init_fd() and close_fd(), plus
725 * a private structure with several pointers to places such as below.
726 */
727
728static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
729#endif
730
willy tarreau0f7af912005-12-17 12:21:26 +0100731static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100732/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100733static char trash[BUFSIZE];
734
willy tarreaudd07e972005-12-18 00:48:48 +0100735const int zero = 0;
736const int one = 1;
737
willy tarreau0f7af912005-12-17 12:21:26 +0100738/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100739 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100740 */
741
742#define MAX_SYSLOG_LEN 1024
743#define NB_LOG_FACILITIES 24
744const char *log_facilities[NB_LOG_FACILITIES] = {
745 "kern", "user", "mail", "daemon",
746 "auth", "syslog", "lpr", "news",
747 "uucp", "cron", "auth2", "ftp",
748 "ntp", "audit", "alert", "cron2",
749 "local0", "local1", "local2", "local3",
750 "local4", "local5", "local6", "local7"
751};
752
753
754#define NB_LOG_LEVELS 8
755const char *log_levels[NB_LOG_LEVELS] = {
756 "emerg", "alert", "crit", "err",
757 "warning", "notice", "info", "debug"
758};
759
760#define SYSLOG_PORT 514
761
762const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
763 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100764
willy tarreaub1285d52005-12-18 01:20:14 +0100765const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100766const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
767const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
768const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
769 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
770 unknown, Set-cookie Rewritten */
771
willy tarreau0f7af912005-12-17 12:21:26 +0100772#define MAX_HOSTNAME_LEN 32
773static char hostname[MAX_HOSTNAME_LEN] = "";
774
willy tarreau8337c6b2005-12-17 13:41:01 +0100775const char *HTTP_302 =
776 "HTTP/1.0 302 Found\r\n"
777 "Cache-Control: no-cache\r\n"
778 "Connection: close\r\n"
779 "Location: "; /* not terminated since it will be concatenated with the URL */
780
willy tarreauc1f47532005-12-18 01:08:26 +0100781/* same as 302 except that the browser MUST retry with the GET method */
782const char *HTTP_303 =
783 "HTTP/1.0 303 See Other\r\n"
784 "Cache-Control: no-cache\r\n"
785 "Connection: close\r\n"
786 "Location: "; /* not terminated since it will be concatenated with the URL */
787
willy tarreaua1598082005-12-17 13:08:06 +0100788const char *HTTP_400 =
789 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100790 "Cache-Control: no-cache\r\n"
791 "Connection: close\r\n"
792 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100793 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100794
willy tarreaua1598082005-12-17 13:08:06 +0100795const char *HTTP_403 =
796 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100797 "Cache-Control: no-cache\r\n"
798 "Connection: close\r\n"
799 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100800 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
801
willy tarreau8337c6b2005-12-17 13:41:01 +0100802const char *HTTP_408 =
803 "HTTP/1.0 408 Request Time-out\r\n"
804 "Cache-Control: no-cache\r\n"
805 "Connection: close\r\n"
806 "\r\n"
807 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
808
willy tarreau750a4722005-12-17 13:21:24 +0100809const char *HTTP_500 =
810 "HTTP/1.0 500 Server Error\r\n"
811 "Cache-Control: no-cache\r\n"
812 "Connection: close\r\n"
813 "\r\n"
814 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100815
816const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100817 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100818 "Cache-Control: no-cache\r\n"
819 "Connection: close\r\n"
820 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100821 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
822
823const char *HTTP_503 =
824 "HTTP/1.0 503 Service Unavailable\r\n"
825 "Cache-Control: no-cache\r\n"
826 "Connection: close\r\n"
827 "\r\n"
828 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
829
830const char *HTTP_504 =
831 "HTTP/1.0 504 Gateway Time-out\r\n"
832 "Cache-Control: no-cache\r\n"
833 "Connection: close\r\n"
834 "\r\n"
835 "<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 +0100836
willy tarreau0f7af912005-12-17 12:21:26 +0100837/*********************************************************************/
838/* statistics ******************************************************/
839/*********************************************************************/
840
willy tarreau750a4722005-12-17 13:21:24 +0100841#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100842static int stats_tsk_lsrch, stats_tsk_rsrch,
843 stats_tsk_good, stats_tsk_right, stats_tsk_left,
844 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100845#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100846
847
848/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100849/* debugging *******************************************************/
850/*********************************************************************/
851#ifdef DEBUG_FULL
852static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
853static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
854#endif
855
856/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100857/* function prototypes *********************************************/
858/*********************************************************************/
859
860int event_accept(int fd);
861int event_cli_read(int fd);
862int event_cli_write(int fd);
863int event_srv_read(int fd);
864int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100865int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100866
willy tarreau12350152005-12-18 01:03:27 +0100867static int appsession_task_init(void);
868static int appsession_init(void);
869static int appsession_refresh(struct task *t);
870
willy tarreau0f7af912005-12-17 12:21:26 +0100871/*********************************************************************/
872/* general purpose functions ***************************************/
873/*********************************************************************/
874
875void display_version() {
876 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100877 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100878}
879
880/*
881 * This function prints the command line usage and exits
882 */
883void usage(char *name) {
884 display_version();
885 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100886 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100887#if STATTIME > 0
888 "sl"
889#endif
willy tarreau746e26b2006-03-25 11:14:35 +0100890 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
891 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100892 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100893 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +0100894 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100895#if STATTIME > 0
896 " -s enables statistics output\n"
897 " -l enables long statistics format\n"
898#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100899 " -D goes daemon ; implies -q\n"
900 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100901 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100902 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +0100903 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100904 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100905 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100906#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100907 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100908#endif
909#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100910 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100911#endif
willy tarreau53e99702006-03-25 18:53:50 +0100912 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100913 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100914 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100915 exit(1);
916}
917
918
919/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100920 * Displays the message on stderr with the date and pid. Overrides the quiet
921 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100922 */
923void Alert(char *fmt, ...) {
924 va_list argp;
925 struct timeval tv;
926 struct tm *tm;
927
willy tarreaud0fb4652005-12-18 01:32:04 +0100928 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100929 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100930
willy tarreau5cbea6f2005-12-17 12:48:26 +0100931 gettimeofday(&tv, NULL);
932 tm=localtime(&tv.tv_sec);
933 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100934 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100935 vfprintf(stderr, fmt, argp);
936 fflush(stderr);
937 va_end(argp);
938 }
willy tarreau0f7af912005-12-17 12:21:26 +0100939}
940
941
942/*
943 * Displays the message on stderr with the date and pid.
944 */
945void Warning(char *fmt, ...) {
946 va_list argp;
947 struct timeval tv;
948 struct tm *tm;
949
willy tarreau982249e2005-12-18 00:57:06 +0100950 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100951 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100952
willy tarreau5cbea6f2005-12-17 12:48:26 +0100953 gettimeofday(&tv, NULL);
954 tm=localtime(&tv.tv_sec);
955 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100956 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100957 vfprintf(stderr, fmt, argp);
958 fflush(stderr);
959 va_end(argp);
960 }
961}
962
963/*
964 * Displays the message on <out> only if quiet mode is not set.
965 */
966void qfprintf(FILE *out, char *fmt, ...) {
967 va_list argp;
968
willy tarreau982249e2005-12-18 00:57:06 +0100969 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100970 va_start(argp, fmt);
971 vfprintf(out, fmt, argp);
972 fflush(out);
973 va_end(argp);
974 }
willy tarreau0f7af912005-12-17 12:21:26 +0100975}
976
977
978/*
979 * converts <str> to a struct sockaddr_in* which is locally allocated.
980 * The format is "addr:port", where "addr" can be empty or "*" to indicate
981 * INADDR_ANY.
982 */
983struct sockaddr_in *str2sa(char *str) {
984 static struct sockaddr_in sa;
985 char *c;
986 int port;
987
willy tarreaua1598082005-12-17 13:08:06 +0100988 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100989 str=strdup(str);
990
991 if ((c=strrchr(str,':')) != NULL) {
992 *c++=0;
993 port=atol(c);
994 }
995 else
996 port=0;
997
998 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
999 sa.sin_addr.s_addr = INADDR_ANY;
1000 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01001001 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001002 struct hostent *he;
1003
1004 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001005 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001006 }
1007 else
1008 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1009 }
1010 sa.sin_port=htons(port);
1011 sa.sin_family=AF_INET;
1012
1013 free(str);
1014 return &sa;
1015}
1016
willy tarreaub1285d52005-12-18 01:20:14 +01001017/*
1018 * converts <str> to a two struct in_addr* which are locally allocated.
1019 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1020 * is optionnal and either in the dotted or CIDR notation.
1021 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1022 */
1023int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1024 char *c;
1025 unsigned long len;
1026
1027 memset(mask, 0, sizeof(*mask));
1028 memset(addr, 0, sizeof(*addr));
1029 str=strdup(str);
1030
1031 if ((c = strrchr(str, '/')) != NULL) {
1032 *c++ = 0;
1033 /* c points to the mask */
1034 if (strchr(c, '.') != NULL) { /* dotted notation */
1035 if (!inet_pton(AF_INET, c, mask))
1036 return 0;
1037 }
1038 else { /* mask length */
1039 char *err;
1040 len = strtol(c, &err, 10);
1041 if (!*c || (err && *err) || (unsigned)len > 32)
1042 return 0;
1043 if (len)
1044 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1045 else
1046 mask->s_addr = 0;
1047 }
1048 }
1049 else {
1050 mask->s_addr = 0xFFFFFFFF;
1051 }
1052 if (!inet_pton(AF_INET, str, addr)) {
1053 struct hostent *he;
1054
1055 if ((he = gethostbyname(str)) == NULL) {
1056 return 0;
1057 }
1058 else
1059 *addr = *(struct in_addr *) *(he->h_addr_list);
1060 }
1061 free(str);
1062 return 1;
1063}
1064
willy tarreau9fe663a2005-12-17 13:02:59 +01001065
1066/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001067 * converts <str> to a list of listeners which are dynamically allocated.
1068 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1069 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1070 * - <port> is a numerical port from 1 to 65535 ;
1071 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1072 * This can be repeated as many times as necessary, separated by a coma.
1073 * The <tail> argument is a pointer to a current list which should be appended
1074 * to the tail of the new list. The pointer to the new list is returned.
1075 */
1076struct listener *str2listener(char *str, struct listener *tail) {
1077 struct listener *l;
1078 char *c, *next, *range, *dupstr;
1079 int port, end;
1080
1081 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001082
willy tarreaua41a8b42005-12-17 14:02:24 +01001083 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001084 struct sockaddr_storage ss;
1085
willy tarreaua41a8b42005-12-17 14:02:24 +01001086 str = next;
1087 /* 1) look for the end of the first address */
1088 if ((next = strrchr(str, ',')) != NULL) {
1089 *next++ = 0;
1090 }
1091
willy tarreau8a86dbf2005-12-18 00:45:59 +01001092 /* 2) look for the addr/port delimiter, it's the last colon. */
1093 if ((range = strrchr(str, ':')) == NULL) {
1094 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001095 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001096 }
1097
1098 *range++ = 0;
1099
1100 if (strrchr(str, ':') != NULL) {
1101 /* IPv6 address contains ':' */
1102 memset(&ss, 0, sizeof(ss));
1103 ss.ss_family = AF_INET6;
1104
1105 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1106 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001107 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001108 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001109 }
1110 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001111 memset(&ss, 0, sizeof(ss));
1112 ss.ss_family = AF_INET;
1113
1114 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1115 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1116 }
1117 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1118 struct hostent *he;
1119
1120 if ((he = gethostbyname(str)) == NULL) {
1121 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001122 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001123 }
1124 else
1125 ((struct sockaddr_in *)&ss)->sin_addr =
1126 *(struct in_addr *) *(he->h_addr_list);
1127 }
1128 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001129
1130 /* 3) look for the port-end delimiter */
1131 if ((c = strchr(range, '-')) != NULL) {
1132 *c++ = 0;
1133 end = atol(c);
1134 }
1135 else {
1136 end = atol(range);
1137 }
1138
willy tarreaud0fb4652005-12-18 01:32:04 +01001139 port = atol(range);
1140
1141 if (port < 1 || port > 65535) {
1142 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1143 goto fail;
1144 }
1145
1146 if (end < 1 || end > 65535) {
1147 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1148 goto fail;
1149 }
1150
1151 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001152 l = (struct listener *)calloc(1, sizeof(struct listener));
1153 l->next = tail;
1154 tail = l;
1155
willy tarreau41310e72006-03-25 18:17:56 +01001156 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001157 l->addr = ss;
1158 if (ss.ss_family == AF_INET6)
1159 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1160 else
1161 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1162
willy tarreaua41a8b42005-12-17 14:02:24 +01001163 } /* end for(port) */
1164 } /* end while(next) */
1165 free(dupstr);
1166 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001167 fail:
1168 free(dupstr);
1169 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001170}
1171
willy tarreau4302f492005-12-18 01:00:37 +01001172
1173#define FD_SETS_ARE_BITFIELDS
1174#ifdef FD_SETS_ARE_BITFIELDS
1175/*
1176 * This map is used with all the FD_* macros to check whether a particular bit
1177 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1178 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1179 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1180 * exclusively to the macros.
1181 */
1182fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1183fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1184
1185#else
1186#error "Check if your OS uses bitfields for fd_sets"
1187#endif
1188
1189/* will try to encode the string <string> replacing all characters tagged in
1190 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1191 * prefixed by <escape>, and will store the result between <start> (included
1192 *) and <stop> (excluded), and will always terminate the string with a '\0'
1193 * before <stop>. The position of the '\0' is returned if the conversion
1194 * completes. If bytes are missing between <start> and <stop>, then the
1195 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1196 * cannot even be stored so we return <start> without writing the 0.
1197 * The input string must also be zero-terminated.
1198 */
1199char hextab[16] = "0123456789ABCDEF";
1200char *encode_string(char *start, char *stop,
1201 const char escape, const fd_set *map,
1202 const char *string)
1203{
1204 if (start < stop) {
1205 stop--; /* reserve one byte for the final '\0' */
1206 while (start < stop && *string != 0) {
1207 if (!FD_ISSET((unsigned char)(*string), map))
1208 *start++ = *string;
1209 else {
1210 if (start + 3 >= stop)
1211 break;
1212 *start++ = escape;
1213 *start++ = hextab[(*string >> 4) & 15];
1214 *start++ = hextab[*string & 15];
1215 }
1216 string++;
1217 }
1218 *start = '\0';
1219 }
1220 return start;
1221}
willy tarreaua41a8b42005-12-17 14:02:24 +01001222
1223/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001224 * This function sends a syslog message to both log servers of a proxy,
1225 * or to global log servers if the proxy is NULL.
1226 * It also tries not to waste too much time computing the message header.
1227 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001228 */
1229void send_log(struct proxy *p, int level, char *message, ...) {
1230 static int logfd = -1; /* syslog UDP socket */
1231 static long tvsec = -1; /* to force the string to be initialized */
1232 struct timeval tv;
1233 va_list argp;
1234 static char logmsg[MAX_SYSLOG_LEN];
1235 static char *dataptr = NULL;
1236 int fac_level;
1237 int hdr_len, data_len;
1238 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001239 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001240 int nbloggers = 0;
1241 char *log_ptr;
1242
1243 if (logfd < 0) {
1244 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1245 return;
1246 }
1247
1248 if (level < 0 || progname == NULL || message == NULL)
1249 return;
1250
1251 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001252 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001253 /* this string is rebuild only once a second */
1254 struct tm *tm = localtime(&tv.tv_sec);
1255 tvsec = tv.tv_sec;
1256
willy tarreauc29948c2005-12-17 13:10:27 +01001257 hdr_len = snprintf(logmsg, sizeof(logmsg),
1258 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1259 monthname[tm->tm_mon],
1260 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1261 progname, pid);
1262 /* WARNING: depending upon implementations, snprintf may return
1263 * either -1 or the number of bytes that would be needed to store
1264 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001265 */
willy tarreauc29948c2005-12-17 13:10:27 +01001266 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1267 hdr_len = sizeof(logmsg);
1268
1269 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001270 }
1271
1272 va_start(argp, message);
1273 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001274 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1275 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001276 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001277 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001278
1279 if (p == NULL) {
1280 if (global.logfac1 >= 0) {
1281 sa[nbloggers] = &global.logsrv1;
1282 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001283 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001284 nbloggers++;
1285 }
1286 if (global.logfac2 >= 0) {
1287 sa[nbloggers] = &global.logsrv2;
1288 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001289 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001290 nbloggers++;
1291 }
1292 } else {
1293 if (p->logfac1 >= 0) {
1294 sa[nbloggers] = &p->logsrv1;
1295 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001296 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001297 nbloggers++;
1298 }
1299 if (p->logfac2 >= 0) {
1300 sa[nbloggers] = &p->logsrv2;
1301 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001302 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001303 nbloggers++;
1304 }
1305 }
1306
1307 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001308 /* we can filter the level of the messages that are sent to each logger */
1309 if (level > loglevel[nbloggers])
1310 continue;
1311
willy tarreauc29948c2005-12-17 13:10:27 +01001312 /* For each target, we may have a different facility.
1313 * We can also have a different log level for each message.
1314 * This induces variations in the message header length.
1315 * Since we don't want to recompute it each time, nor copy it every
1316 * time, we only change the facility in the pre-computed header,
1317 * and we change the pointer to the header accordingly.
1318 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001319 fac_level = (facilities[nbloggers] << 3) + level;
1320 log_ptr = logmsg + 3; /* last digit of the log level */
1321 do {
1322 *log_ptr = '0' + fac_level % 10;
1323 fac_level /= 10;
1324 log_ptr--;
1325 } while (fac_level && log_ptr > logmsg);
1326 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001327
willy tarreauc29948c2005-12-17 13:10:27 +01001328 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001329
1330#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001331 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001332 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1333#else
willy tarreauc29948c2005-12-17 13:10:27 +01001334 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001335 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1336#endif
1337 }
willy tarreau0f7af912005-12-17 12:21:26 +01001338}
1339
1340
1341/* sets <tv> to the current time */
1342static inline struct timeval *tv_now(struct timeval *tv) {
1343 if (tv)
1344 gettimeofday(tv, NULL);
1345 return tv;
1346}
1347
1348/*
1349 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1350 */
1351static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1352 if (!tv || !from)
1353 return NULL;
1354 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1355 tv->tv_sec = from->tv_sec + (ms/1000);
1356 while (tv->tv_usec >= 1000000) {
1357 tv->tv_usec -= 1000000;
1358 tv->tv_sec++;
1359 }
1360 return tv;
1361}
1362
1363/*
1364 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001365 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001366 */
1367static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001368 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001369 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001370 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001371 return 1;
1372 else if (tv1->tv_usec < tv2->tv_usec)
1373 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001374 else if (tv1->tv_usec > tv2->tv_usec)
1375 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001376 else
1377 return 0;
1378}
1379
1380/*
1381 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001382 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001383 */
1384unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1385 int cmp;
1386 unsigned long ret;
1387
1388
willy tarreauef900ab2005-12-17 12:52:52 +01001389 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001390 if (!cmp)
1391 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001392 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001393 struct timeval *tmp = tv1;
1394 tv1 = tv2;
1395 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001396 }
willy tarreauef900ab2005-12-17 12:52:52 +01001397 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001398 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001399 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001400 else
willy tarreauef900ab2005-12-17 12:52:52 +01001401 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001402 return (unsigned long) ret;
1403}
1404
1405/*
willy tarreau750a4722005-12-17 13:21:24 +01001406 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001407 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001408 */
1409static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1410 unsigned long ret;
1411
willy tarreau6e682ce2005-12-17 13:26:49 +01001412 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1413 if (tv2->tv_usec > tv1->tv_usec)
1414 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001415 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001416 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001417 return (unsigned long) ret;
1418}
1419
1420/*
willy tarreau0f7af912005-12-17 12:21:26 +01001421 * 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 +01001422 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001423 */
1424static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001425 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001426 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001427 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001428 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001429 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001430 else
1431 return 0;
1432 }
willy tarreau0f7af912005-12-17 12:21:26 +01001433 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001434 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001435 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001436 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001437 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001438 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001439 else
1440 return 0;
1441}
1442
1443/*
1444 * returns the remaining time between tv1=now and event=tv2
1445 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001446 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001447 */
1448static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1449 unsigned long ret;
1450
willy tarreau0f7af912005-12-17 12:21:26 +01001451 if (tv_cmp_ms(tv1, tv2) >= 0)
1452 return 0; /* event elapsed */
1453
willy tarreauef900ab2005-12-17 12:52:52 +01001454 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001455 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001456 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001457 else
willy tarreauef900ab2005-12-17 12:52:52 +01001458 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001459 return (unsigned long) ret;
1460}
1461
1462
1463/*
1464 * zeroes a struct timeval
1465 */
1466
1467static inline struct timeval *tv_eternity(struct timeval *tv) {
1468 tv->tv_sec = tv->tv_usec = 0;
1469 return tv;
1470}
1471
1472/*
1473 * returns 1 if tv is null, else 0
1474 */
1475static inline int tv_iseternity(struct timeval *tv) {
1476 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1477 return 1;
1478 else
1479 return 0;
1480}
1481
1482/*
1483 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1484 * considering that 0 is the eternity.
1485 */
1486static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1487 if (tv_iseternity(tv1))
1488 if (tv_iseternity(tv2))
1489 return 0; /* same */
1490 else
1491 return 1; /* tv1 later than tv2 */
1492 else if (tv_iseternity(tv2))
1493 return -1; /* tv2 later than tv1 */
1494
1495 if (tv1->tv_sec > tv2->tv_sec)
1496 return 1;
1497 else if (tv1->tv_sec < tv2->tv_sec)
1498 return -1;
1499 else if (tv1->tv_usec > tv2->tv_usec)
1500 return 1;
1501 else if (tv1->tv_usec < tv2->tv_usec)
1502 return -1;
1503 else
1504 return 0;
1505}
1506
1507/*
1508 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1509 * considering that 0 is the eternity.
1510 */
1511static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1512 if (tv_iseternity(tv1))
1513 if (tv_iseternity(tv2))
1514 return 0; /* same */
1515 else
1516 return 1; /* tv1 later than tv2 */
1517 else if (tv_iseternity(tv2))
1518 return -1; /* tv2 later than tv1 */
1519
willy tarreauefae1842005-12-17 12:51:03 +01001520 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001521 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001522 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001523 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001524 return -1;
1525 else
1526 return 0;
1527 }
1528 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001529 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001530 return 1;
1531 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001532 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001533 return -1;
1534 else
1535 return 0;
1536}
1537
1538/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001539 * returns the remaining time between tv1=now and event=tv2
1540 * if tv2 is passed, 0 is returned.
1541 * Returns TIME_ETERNITY if tv2 is eternity.
1542 */
1543static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1544 unsigned long ret;
1545
1546 if (tv_iseternity(tv2))
1547 return TIME_ETERNITY;
1548
1549 if (tv_cmp_ms(tv1, tv2) >= 0)
1550 return 0; /* event elapsed */
1551
1552 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1553 if (tv2->tv_usec > tv1->tv_usec)
1554 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1555 else
1556 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1557 return (unsigned long) ret;
1558}
1559
1560/*
willy tarreau0f7af912005-12-17 12:21:26 +01001561 * returns the first event between tv1 and tv2 into tvmin.
1562 * a zero tv is ignored. tvmin is returned.
1563 */
1564static inline struct timeval *tv_min(struct timeval *tvmin,
1565 struct timeval *tv1, struct timeval *tv2) {
1566
1567 if (tv_cmp2(tv1, tv2) <= 0)
1568 *tvmin = *tv1;
1569 else
1570 *tvmin = *tv2;
1571
1572 return tvmin;
1573}
1574
1575
1576
1577/***********************************************************/
1578/* fd management ***************************************/
1579/***********************************************************/
1580
1581
1582
willy tarreau5cbea6f2005-12-17 12:48:26 +01001583/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1584 * The file descriptor is also closed.
1585 */
willy tarreau0f7af912005-12-17 12:21:26 +01001586static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001587 FD_CLR(fd, StaticReadEvent);
1588 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001589#if defined(ENABLE_EPOLL)
1590 if (PrevReadEvent) {
1591 FD_CLR(fd, PrevReadEvent);
1592 FD_CLR(fd, PrevWriteEvent);
1593 }
1594#endif
1595
willy tarreau5cbea6f2005-12-17 12:48:26 +01001596 close(fd);
1597 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001598
1599 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1600 maxfd--;
1601}
1602
1603/* recomputes the maxfd limit from the fd */
1604static inline void fd_insert(int fd) {
1605 if (fd+1 > maxfd)
1606 maxfd = fd+1;
1607}
1608
1609/*************************************************************/
1610/* task management ***************************************/
1611/*************************************************************/
1612
willy tarreau5cbea6f2005-12-17 12:48:26 +01001613/* puts the task <t> in run queue <q>, and returns <t> */
1614static inline struct task *task_wakeup(struct task **q, struct task *t) {
1615 if (t->state == TASK_RUNNING)
1616 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001617 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001618 t->rqnext = *q;
1619 t->state = TASK_RUNNING;
1620 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001621 }
1622}
1623
willy tarreau5cbea6f2005-12-17 12:48:26 +01001624/* removes the task <t> from the queue <q>
1625 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001626 * set the run queue to point to the next one, and return it
1627 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001628static inline struct task *task_sleep(struct task **q, struct task *t) {
1629 if (t->state == TASK_RUNNING) {
1630 *q = t->rqnext;
1631 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001632 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001633 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001634}
1635
1636/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001637 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001638 * from the run queue. A pointer to the task itself is returned.
1639 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001640static inline struct task *task_delete(struct task *t) {
1641 t->prev->next = t->next;
1642 t->next->prev = t->prev;
1643 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001644}
1645
1646/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001647 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001648 */
1649static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001650 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001651}
1652
willy tarreau5cbea6f2005-12-17 12:48:26 +01001653/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001654 * may be only moved or left where it was, depending on its timing requirements.
1655 * <task> is returned.
1656 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001657struct task *task_queue(struct task *task) {
1658 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001659 struct task *start_from;
1660
1661 /* first, test if the task was already in a list */
1662 if (task->prev == NULL) {
1663 // start_from = list;
1664 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001665#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001666 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001667#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001668 /* insert the unlinked <task> into the list, searching back from the last entry */
1669 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1670 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001671#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001672 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001673#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001674 }
1675
1676 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1677 // start_from = start_from->next;
1678 // stats_tsk_nsrch++;
1679 // }
1680 }
1681 else if (task->prev == list ||
1682 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1683 start_from = task->next;
1684 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001685#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001686 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001687#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001688 return task; /* it's already in the right place */
1689 }
1690
willy tarreau750a4722005-12-17 13:21:24 +01001691#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001692 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001693#endif
1694
1695 /* if the task is not at the right place, there's little chance that
1696 * it has only shifted a bit, and it will nearly always be queued
1697 * at the end of the list because of constant timeouts
1698 * (observed in real case).
1699 */
1700#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1701 start_from = list->prev; /* assume we'll queue to the end of the list */
1702 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1703 start_from = start_from->prev;
1704#if STATTIME > 0
1705 stats_tsk_lsrch++;
1706#endif
1707 }
1708#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001709 /* insert the unlinked <task> into the list, searching after position <start_from> */
1710 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1711 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001712#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001713 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001714#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001715 }
willy tarreau750a4722005-12-17 13:21:24 +01001716#endif /* WE_REALLY_... */
1717
willy tarreau0f7af912005-12-17 12:21:26 +01001718 /* we need to unlink it now */
1719 task_delete(task);
1720 }
1721 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001722#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001723 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001724#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001725#ifdef LEFT_TO_TOP /* not very good */
1726 start_from = list;
1727 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1728 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001729#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001730 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001731#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001732 }
1733#else
1734 start_from = task->prev->prev; /* valid because of the previous test above */
1735 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1736 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001737#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001738 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001739#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001740 }
1741#endif
1742 /* we need to unlink it now */
1743 task_delete(task);
1744 }
1745 task->prev = start_from;
1746 task->next = start_from->next;
1747 task->next->prev = task;
1748 start_from->next = task;
1749 return task;
1750}
1751
1752
1753/*********************************************************************/
1754/* more specific functions ***************************************/
1755/*********************************************************************/
1756
1757/* some prototypes */
1758static int maintain_proxies(void);
1759
willy tarreaub952e1d2005-12-18 01:31:20 +01001760/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001761 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1762 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001763static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001764#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001765 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1766#else
willy tarreaua1598082005-12-17 13:08:06 +01001767#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001768 return getsockname(fd, (struct sockaddr *)sa, salen);
1769#else
1770 return -1;
1771#endif
1772#endif
1773}
1774
1775/*
1776 * frees the context associated to a session. It must have been removed first.
1777 */
1778static inline void session_free(struct session *s) {
1779 if (s->req)
1780 pool_free(buffer, s->req);
1781 if (s->rep)
1782 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001783
1784 if (s->rsp_cap != NULL) {
1785 struct cap_hdr *h;
1786 for (h = s->proxy->rsp_cap; h; h = h->next) {
1787 if (s->rsp_cap[h->index] != NULL)
1788 pool_free_to(h->pool, s->rsp_cap[h->index]);
1789 }
1790 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1791 }
1792 if (s->req_cap != NULL) {
1793 struct cap_hdr *h;
1794 for (h = s->proxy->req_cap; h; h = h->next) {
1795 if (s->req_cap[h->index] != NULL)
1796 pool_free_to(h->pool, s->req_cap[h->index]);
1797 }
1798 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1799 }
1800
willy tarreaua1598082005-12-17 13:08:06 +01001801 if (s->logs.uri)
1802 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001803 if (s->logs.cli_cookie)
1804 pool_free(capture, s->logs.cli_cookie);
1805 if (s->logs.srv_cookie)
1806 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001807
willy tarreau5cbea6f2005-12-17 12:48:26 +01001808 pool_free(session, s);
1809}
1810
willy tarreau0f7af912005-12-17 12:21:26 +01001811
1812/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01001813 * This function recounts the number of usable active and backup servers for
1814 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
1815 */
1816static inline void recount_servers(struct proxy *px) {
1817 struct server *srv;
1818
1819 px->srv_act = 0; px->srv_bck = 0;
1820 for (srv = px->srv; srv != NULL; srv = srv->next) {
1821 if (srv->state & SRV_RUNNING) {
1822 if (srv->state & SRV_BACKUP)
1823 px->srv_bck++;
1824 else
1825 px->srv_act++;
1826 }
1827 }
1828}
1829
1830/*
1831 * This function tries to find a running server for the proxy <px> following
1832 * the round-robin method. Depending on the number of active/backup servers,
1833 * it will either look for active servers, or for backup servers.
1834 * If any server is found, it will be returned and px->cursrv will be updated
1835 * to point to the next server. If no valid server is found, NULL is returned.
willy tarreau8337c6b2005-12-17 13:41:01 +01001836 */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001837static inline struct server *get_server_rr(struct proxy *px) {
1838 struct server *srv;
willy tarreau72e583d2006-03-23 11:27:02 +01001839 struct server *end;
willy tarreau8337c6b2005-12-17 13:41:01 +01001840
willy tarreau4c8c2b52006-03-24 19:36:41 +01001841 if (px->srv_act) {
1842 srv = px->cursrv;
willy tarreau72e583d2006-03-23 11:27:02 +01001843 if (srv == NULL)
1844 srv = px->srv;
1845 end = srv;
willy tarreau8337c6b2005-12-17 13:41:01 +01001846 do {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001847 if ((srv->state & (SRV_RUNNING | SRV_BACKUP)) == SRV_RUNNING) {
1848 px->cursrv = srv->next;
willy tarreau8337c6b2005-12-17 13:41:01 +01001849 return srv;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001850 }
1851
willy tarreau8337c6b2005-12-17 13:41:01 +01001852 srv = srv->next;
willy tarreau72e583d2006-03-23 11:27:02 +01001853 if (srv == NULL)
1854 srv = px->srv;
1855 } while (srv != end);
willy tarreau4c8c2b52006-03-24 19:36:41 +01001856 /* note that theorically we should not get there */
1857 }
Willy TARREAU3481c462006-03-01 22:37:57 +01001858
willy tarreau4c8c2b52006-03-24 19:36:41 +01001859 if (px->srv_bck) {
Willy TARREAU3481c462006-03-01 22:37:57 +01001860 /* By default, we look for the first backup server if all others are
1861 * DOWN. But in some cases, it may be desirable to load-balance across
1862 * all backup servers.
1863 */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001864 if (px->options & PR_O_USE_ALL_BK)
1865 srv = px->cursrv;
1866 else
1867 srv = px->srv;
1868
1869 if (srv == NULL)
Willy TARREAU3481c462006-03-01 22:37:57 +01001870 srv = px->srv;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001871 end = srv;
1872 do {
1873 if (srv->state & SRV_RUNNING) {
1874 px->cursrv = srv->next;
1875 return srv;
1876 }
1877 srv = srv->next;
1878 if (srv == NULL)
1879 srv = px->srv;
1880 } while (srv != end);
1881 /* note that theorically we should not get there */
1882 }
Willy TARREAU3481c462006-03-01 22:37:57 +01001883
willy tarreau4c8c2b52006-03-24 19:36:41 +01001884 /* if we get there, it means there are no available servers at all */
willy tarreau8337c6b2005-12-17 13:41:01 +01001885 return NULL;
1886}
1887
willy tarreau62084d42006-03-24 18:57:41 +01001888
1889/*
willy tarreau1a3442d2006-03-24 21:03:20 +01001890 * This function tries to find a running server for the proxy <px> following
1891 * the source hash method. Depending on the number of active/backup servers,
1892 * it will either look for active servers, or for backup servers.
1893 * If any server is found, it will be returned. If no valid server is found,
1894 * NULL is returned.
1895 */
1896static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
1897 struct server *srv;
1898
1899 if (px->srv_act) {
1900 unsigned int h, l;
1901
1902 l = h = 0;
1903 if (px->srv_act > 1) {
1904 while ((l + sizeof (int)) <= len) {
1905 h ^= ntohl(*(unsigned int *)(&addr[l]));
1906 l += sizeof (int);
1907 }
1908 h %= px->srv_act;
1909 }
1910
1911 for (srv = px->srv; srv; srv = srv->next) {
1912 if ((srv->state & (SRV_RUNNING | SRV_BACKUP)) == SRV_RUNNING) {
1913 if (!h)
1914 return srv;
1915 h--;
1916 }
1917 }
1918 /* note that theorically we should not get there */
1919 }
1920
1921 if (px->srv_bck) {
1922 unsigned int h, l;
1923
1924 /* By default, we look for the first backup server if all others are
1925 * DOWN. But in some cases, it may be desirable to load-balance across
1926 * all backup servers.
1927 */
1928 l = h = 0;
1929 if (px->srv_bck > 1 && px->options & PR_O_USE_ALL_BK) {
1930 while ((l + sizeof (int)) <= len) {
1931 h ^= ntohl(*(unsigned int *)(&addr[l]));
1932 l += sizeof (int);
1933 }
1934 h %= px->srv_bck;
1935 }
1936
1937 for (srv = px->srv; srv; srv = srv->next) {
1938 if (srv->state & SRV_RUNNING) {
1939 if (!h)
1940 return srv;
1941 h--;
1942 }
1943 }
1944 /* note that theorically we should not get there */
1945 }
1946
1947 /* if we get there, it means there are no available servers at all */
1948 return NULL;
1949}
1950
1951
1952/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001953 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01001954 * is set, or to the dispatch server if (s->direct) is 0.
1955 * It can return one of :
1956 * - SN_ERR_NONE if everything's OK
1957 * - SN_ERR_SRVTO if there are no more servers
1958 * - SN_ERR_SRVCL if the connection was refused by the server
1959 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1960 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1961 * - SN_ERR_INTERNAL for any other purely internal errors
1962 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01001963 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001964int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001965 int fd;
1966
willy tarreau12350152005-12-18 01:03:27 +01001967#ifdef DEBUG_FULL
1968 fprintf(stderr,"connect_server : s=%p\n",s);
1969#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001970
willy tarreaue39cd132005-12-17 13:00:18 +01001971 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001972 s->srv_addr = s->srv->addr;
1973 }
1974 else if (s->proxy->options & PR_O_BALANCE) {
willy tarreau1a3442d2006-03-24 21:03:20 +01001975 /* Ensure that srv will not be NULL */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001976 if (!s->proxy->srv_act && !s->proxy->srv_bck)
1977 return SN_ERR_SRVTO;
1978
willy tarreau5cbea6f2005-12-17 12:48:26 +01001979 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001980 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001981
willy tarreau4c8c2b52006-03-24 19:36:41 +01001982 srv = get_server_rr(s->proxy);
willy tarreau8337c6b2005-12-17 13:41:01 +01001983 s->srv_addr = srv->addr;
1984 s->srv = srv;
willy tarreau0f7af912005-12-17 12:21:26 +01001985 }
willy tarreau1a3442d2006-03-24 21:03:20 +01001986 else if (s->proxy->options & PR_O_BALANCE_SH) {
1987 struct server *srv;
1988 int len;
1989
1990 if (s->cli_addr.ss_family == AF_INET)
1991 len = 4;
1992 else if (s->cli_addr.ss_family == AF_INET6)
1993 len = 16;
1994 else /* unknown IP family */
1995 return SN_ERR_INTERNAL;
1996
1997 srv = get_server_sh(s->proxy,
1998 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
1999 len);
2000 s->srv_addr = srv->addr;
2001 s->srv = srv;
2002 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002003 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01002004 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002005 }
willy tarreaua1598082005-12-17 13:08:06 +01002006 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002007 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002008 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002009 }
2010 else if (s->proxy->options & PR_O_TRANSP) {
2011 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002012 socklen_t salen = sizeof(s->srv_addr);
2013
willy tarreau5cbea6f2005-12-17 12:48:26 +01002014 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2015 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002016 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002017 }
2018 }
willy tarreau0f7af912005-12-17 12:21:26 +01002019
willy tarreaua41a8b42005-12-17 14:02:24 +01002020 /* if this server remaps proxied ports, we'll use
2021 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01002022 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01002023 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002024 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01002025
willy tarreaub952e1d2005-12-18 01:31:20 +01002026 if (!(s->proxy->options & PR_O_TRANSP) ||
2027 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01002028 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2029 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
2030 }
2031
willy tarreau0f7af912005-12-17 12:21:26 +01002032 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002033 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002034
2035 if (errno == ENFILE)
2036 send_log(s->proxy, LOG_EMERG,
2037 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2038 s->proxy->id, maxfd);
2039 else if (errno == EMFILE)
2040 send_log(s->proxy, LOG_EMERG,
2041 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2042 s->proxy->id, maxfd);
2043 else if (errno == ENOBUFS || errno == ENOMEM)
2044 send_log(s->proxy, LOG_EMERG,
2045 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2046 s->proxy->id, maxfd);
2047 /* this is a resource error */
2048 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002049 }
2050
willy tarreau9fe663a2005-12-17 13:02:59 +01002051 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002052 /* do not log anything there, it's a normal condition when this option
2053 * is used to serialize connections to a server !
2054 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002055 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2056 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002057 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002058 }
2059
willy tarreau0f7af912005-12-17 12:21:26 +01002060 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2061 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002062 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002063 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002064 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002065 }
2066
willy tarreaub952e1d2005-12-18 01:31:20 +01002067 if (s->proxy->options & PR_O_TCP_SRV_KA)
2068 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2069
willy tarreau0174f312005-12-18 01:02:42 +01002070 /* allow specific binding :
2071 * - server-specific at first
2072 * - proxy-specific next
2073 */
2074 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2075 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2076 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2077 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2078 s->proxy->id, s->srv->id);
2079 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002080 send_log(s->proxy, LOG_EMERG,
2081 "Cannot bind to source address before connect() for server %s/%s.\n",
2082 s->proxy->id, s->srv->id);
2083 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002084 }
2085 }
2086 else if (s->proxy->options & PR_O_BIND_SRC) {
2087 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2088 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2089 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2090 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002091 send_log(s->proxy, LOG_EMERG,
2092 "Cannot bind to source address before connect() for server %s/%s.\n",
2093 s->proxy->id, s->srv->id);
2094 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002095 }
willy tarreaua1598082005-12-17 13:08:06 +01002096 }
2097
willy tarreaub1285d52005-12-18 01:20:14 +01002098 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2099 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2100
2101 if (errno == EAGAIN || errno == EADDRINUSE) {
2102 char *msg;
2103 if (errno == EAGAIN) /* no free ports left, try again later */
2104 msg = "no free ports";
2105 else
2106 msg = "local address already in use";
2107
2108 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002109 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002110 send_log(s->proxy, LOG_EMERG,
2111 "Connect() failed for server %s/%s: %s.\n",
2112 s->proxy->id, s->srv->id, msg);
2113 return SN_ERR_RESOURCE;
2114 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002115 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002116 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002117 return SN_ERR_SRVTO;
2118 } else {
2119 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002120 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002121 close(fd);
2122 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002123 }
2124 }
2125
willy tarreau5cbea6f2005-12-17 12:48:26 +01002126 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002127 fdtab[fd].read = &event_srv_read;
2128 fdtab[fd].write = &event_srv_write;
2129 fdtab[fd].state = FD_STCONN; /* connection in progress */
2130
2131 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002132#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2133 if (PrevReadEvent) {
2134 assert(!(FD_ISSET(fd, PrevReadEvent)));
2135 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2136 }
2137#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002138
2139 fd_insert(fd);
willy tarreauc1364612006-04-07 16:28:28 +02002140 s->srv->cur_sess++;
willy tarreau0f7af912005-12-17 12:21:26 +01002141
2142 if (s->proxy->contimeout)
2143 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2144 else
2145 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002146 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002147}
2148
2149/*
2150 * this function is called on a read event from a client socket.
2151 * It returns 0.
2152 */
2153int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002154 struct task *t = fdtab[fd].owner;
2155 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002156 struct buffer *b = s->req;
2157 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002158
willy tarreau12350152005-12-18 01:03:27 +01002159#ifdef DEBUG_FULL
2160 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2161#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002162
willy tarreau0f7af912005-12-17 12:21:26 +01002163 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002164#ifdef FILL_BUFFERS
2165 while (1)
2166#else
2167 do
2168#endif
2169 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002170 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2171 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002172 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002173 }
2174 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002175 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002176 }
2177 else {
2178 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002179 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2180 * since it means that the rewrite protection has been removed. This
2181 * implies that the if statement can be removed.
2182 */
2183 if (max > b->rlim - b->data)
2184 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002185 }
2186
2187 if (max == 0) { /* not anymore room to store data */
2188 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002189 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002190 }
2191
willy tarreau3242e862005-12-17 12:27:53 +01002192#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002193 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002194 int skerr;
2195 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002196
willy tarreau5cbea6f2005-12-17 12:48:26 +01002197 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2198 if (skerr)
2199 ret = -1;
2200 else
2201 ret = recv(fd, b->r, max, 0);
2202 }
willy tarreau3242e862005-12-17 12:27:53 +01002203#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002204 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002205#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002206 if (ret > 0) {
2207 b->r += ret;
2208 b->l += ret;
2209 s->res_cr = RES_DATA;
2210
2211 if (b->r == b->data + BUFSIZE) {
2212 b->r = b->data; /* wrap around the buffer */
2213 }
willy tarreaua1598082005-12-17 13:08:06 +01002214
2215 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002216 /* we hope to read more data or to get a close on next round */
2217 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002218 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002219 else if (ret == 0) {
2220 s->res_cr = RES_NULL;
2221 break;
2222 }
2223 else if (errno == EAGAIN) {/* ignore EAGAIN */
2224 break;
2225 }
2226 else {
2227 s->res_cr = RES_ERROR;
2228 fdtab[fd].state = FD_STERROR;
2229 break;
2230 }
2231 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002232#ifndef FILL_BUFFERS
2233 while (0);
2234#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002235 }
2236 else {
2237 s->res_cr = RES_ERROR;
2238 fdtab[fd].state = FD_STERROR;
2239 }
2240
willy tarreau5cbea6f2005-12-17 12:48:26 +01002241 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002242 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002243 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2244 else
2245 tv_eternity(&s->crexpire);
2246
2247 task_wakeup(&rq, t);
2248 }
willy tarreau0f7af912005-12-17 12:21:26 +01002249
willy tarreau0f7af912005-12-17 12:21:26 +01002250 return 0;
2251}
2252
2253
2254/*
2255 * this function is called on a read event from a server socket.
2256 * It returns 0.
2257 */
2258int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002259 struct task *t = fdtab[fd].owner;
2260 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002261 struct buffer *b = s->rep;
2262 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002263
willy tarreau12350152005-12-18 01:03:27 +01002264#ifdef DEBUG_FULL
2265 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2266#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002267
willy tarreau0f7af912005-12-17 12:21:26 +01002268 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002269#ifdef FILL_BUFFERS
2270 while (1)
2271#else
2272 do
2273#endif
2274 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002275 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2276 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002277 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002278 }
2279 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002280 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002281 }
2282 else {
2283 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002284 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2285 * since it means that the rewrite protection has been removed. This
2286 * implies that the if statement can be removed.
2287 */
2288 if (max > b->rlim - b->data)
2289 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002290 }
2291
2292 if (max == 0) { /* not anymore room to store data */
2293 FD_CLR(fd, StaticReadEvent);
2294 break;
2295 }
2296
willy tarreau3242e862005-12-17 12:27:53 +01002297#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002298 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002299 int skerr;
2300 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002301
willy tarreau5cbea6f2005-12-17 12:48:26 +01002302 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2303 if (skerr)
2304 ret = -1;
2305 else
2306 ret = recv(fd, b->r, max, 0);
2307 }
willy tarreau3242e862005-12-17 12:27:53 +01002308#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002309 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002310#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002311 if (ret > 0) {
2312 b->r += ret;
2313 b->l += ret;
2314 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002315
willy tarreau5cbea6f2005-12-17 12:48:26 +01002316 if (b->r == b->data + BUFSIZE) {
2317 b->r = b->data; /* wrap around the buffer */
2318 }
willy tarreaua1598082005-12-17 13:08:06 +01002319
2320 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002321 /* we hope to read more data or to get a close on next round */
2322 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002323 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002324 else if (ret == 0) {
2325 s->res_sr = RES_NULL;
2326 break;
2327 }
2328 else if (errno == EAGAIN) {/* ignore EAGAIN */
2329 break;
2330 }
2331 else {
2332 s->res_sr = RES_ERROR;
2333 fdtab[fd].state = FD_STERROR;
2334 break;
2335 }
2336 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002337#ifndef FILL_BUFFERS
2338 while (0);
2339#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002340 }
2341 else {
2342 s->res_sr = RES_ERROR;
2343 fdtab[fd].state = FD_STERROR;
2344 }
2345
willy tarreau5cbea6f2005-12-17 12:48:26 +01002346 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002347 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002348 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2349 else
2350 tv_eternity(&s->srexpire);
2351
2352 task_wakeup(&rq, t);
2353 }
willy tarreau0f7af912005-12-17 12:21:26 +01002354
willy tarreau0f7af912005-12-17 12:21:26 +01002355 return 0;
2356}
2357
2358/*
2359 * this function is called on a write event from a client socket.
2360 * It returns 0.
2361 */
2362int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002363 struct task *t = fdtab[fd].owner;
2364 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002365 struct buffer *b = s->rep;
2366 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002367
willy tarreau12350152005-12-18 01:03:27 +01002368#ifdef DEBUG_FULL
2369 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2370#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002371
2372 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002373 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002374 // max = BUFSIZE; BUG !!!!
2375 max = 0;
2376 }
2377 else if (b->r > b->w) {
2378 max = b->r - b->w;
2379 }
2380 else
2381 max = b->data + BUFSIZE - b->w;
2382
willy tarreau0f7af912005-12-17 12:21:26 +01002383 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002384 if (max == 0) {
2385 s->res_cw = RES_NULL;
2386 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002387 tv_eternity(&s->cwexpire);
2388 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002389 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002390 }
2391
willy tarreau3242e862005-12-17 12:27:53 +01002392#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002393 {
2394 int skerr;
2395 socklen_t lskerr = sizeof(skerr);
2396
2397 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2398 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002399 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002400 else
willy tarreau3242e862005-12-17 12:27:53 +01002401 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002402 }
willy tarreau3242e862005-12-17 12:27:53 +01002403#else
willy tarreau0f7af912005-12-17 12:21:26 +01002404 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002405#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002406
2407 if (ret > 0) {
2408 b->l -= ret;
2409 b->w += ret;
2410
2411 s->res_cw = RES_DATA;
2412
2413 if (b->w == b->data + BUFSIZE) {
2414 b->w = b->data; /* wrap around the buffer */
2415 }
2416 }
2417 else if (ret == 0) {
2418 /* nothing written, just make as if we were never called */
2419// s->res_cw = RES_NULL;
2420 return 0;
2421 }
2422 else if (errno == EAGAIN) /* ignore EAGAIN */
2423 return 0;
2424 else {
2425 s->res_cw = RES_ERROR;
2426 fdtab[fd].state = FD_STERROR;
2427 }
2428 }
2429 else {
2430 s->res_cw = RES_ERROR;
2431 fdtab[fd].state = FD_STERROR;
2432 }
2433
willy tarreaub1ff9db2005-12-17 13:51:03 +01002434 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002435 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002436 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2437 s->crexpire = s->cwexpire;
2438 }
willy tarreau0f7af912005-12-17 12:21:26 +01002439 else
2440 tv_eternity(&s->cwexpire);
2441
willy tarreau5cbea6f2005-12-17 12:48:26 +01002442 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002443 return 0;
2444}
2445
2446
2447/*
2448 * this function is called on a write event from a server socket.
2449 * It returns 0.
2450 */
2451int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002452 struct task *t = fdtab[fd].owner;
2453 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002454 struct buffer *b = s->req;
2455 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002456
willy tarreau12350152005-12-18 01:03:27 +01002457#ifdef DEBUG_FULL
2458 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2459#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002460
2461 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002462 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002463 // max = BUFSIZE; BUG !!!!
2464 max = 0;
2465 }
2466 else if (b->r > b->w) {
2467 max = b->r - b->w;
2468 }
2469 else
2470 max = b->data + BUFSIZE - b->w;
2471
willy tarreau0f7af912005-12-17 12:21:26 +01002472 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002473 if (max == 0) {
2474 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002475 if (s->srv_state == SV_STCONN) {
2476 int skerr;
2477 socklen_t lskerr = sizeof(skerr);
2478 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2479 if (skerr) {
2480 s->res_sw = RES_ERROR;
2481 fdtab[fd].state = FD_STERROR;
2482 task_wakeup(&rq, t);
2483 tv_eternity(&s->swexpire);
2484 FD_CLR(fd, StaticWriteEvent);
2485 return 0;
2486 }
2487 }
2488
willy tarreau0f7af912005-12-17 12:21:26 +01002489 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002490 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002491 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002492 tv_eternity(&s->swexpire);
2493 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002494 return 0;
2495 }
2496
willy tarreau3242e862005-12-17 12:27:53 +01002497#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002498 {
2499 int skerr;
2500 socklen_t lskerr = sizeof(skerr);
2501 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2502 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002503 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002504 else
willy tarreau3242e862005-12-17 12:27:53 +01002505 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002506 }
willy tarreau3242e862005-12-17 12:27:53 +01002507#else
willy tarreau0f7af912005-12-17 12:21:26 +01002508 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002509#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002510 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002511 if (ret > 0) {
2512 b->l -= ret;
2513 b->w += ret;
2514
2515 s->res_sw = RES_DATA;
2516
2517 if (b->w == b->data + BUFSIZE) {
2518 b->w = b->data; /* wrap around the buffer */
2519 }
2520 }
2521 else if (ret == 0) {
2522 /* nothing written, just make as if we were never called */
2523 // s->res_sw = RES_NULL;
2524 return 0;
2525 }
2526 else if (errno == EAGAIN) /* ignore EAGAIN */
2527 return 0;
2528 else {
2529 s->res_sw = RES_ERROR;
2530 fdtab[fd].state = FD_STERROR;
2531 }
2532 }
2533 else {
2534 s->res_sw = RES_ERROR;
2535 fdtab[fd].state = FD_STERROR;
2536 }
2537
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002538 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2539 * otherwise it could loop indefinitely !
2540 */
2541 if (s->srv_state != SV_STCONN) {
2542 if (s->proxy->srvtimeout) {
2543 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
2544 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2545 s->srexpire = s->swexpire;
2546 }
2547 else
2548 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002549 }
willy tarreau0f7af912005-12-17 12:21:26 +01002550
willy tarreau5cbea6f2005-12-17 12:48:26 +01002551 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002552 return 0;
2553}
2554
2555
2556/*
willy tarreaue39cd132005-12-17 13:00:18 +01002557 * returns a message to the client ; the connection is shut down for read,
2558 * and the request is cleared so that no server connection can be initiated.
2559 * The client must be in a valid state for this (HEADER, DATA ...).
2560 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002561 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002562 */
2563void client_retnclose(struct session *s, int len, const char *msg) {
2564 FD_CLR(s->cli_fd, StaticReadEvent);
2565 FD_SET(s->cli_fd, StaticWriteEvent);
2566 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002567 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002568 shutdown(s->cli_fd, SHUT_RD);
2569 s->cli_state = CL_STSHUTR;
2570 strcpy(s->rep->data, msg);
2571 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002572 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002573 s->rep->r += len;
2574 s->req->l = 0;
2575}
2576
2577
2578/*
2579 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002580 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002581 */
2582void client_return(struct session *s, int len, const char *msg) {
2583 strcpy(s->rep->data, msg);
2584 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002585 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002586 s->rep->r += len;
2587 s->req->l = 0;
2588}
2589
willy tarreau9fe663a2005-12-17 13:02:59 +01002590/*
2591 * send a log for the session when we have enough info about it
2592 */
2593void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002594 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002595 struct proxy *p = s->proxy;
2596 int log;
2597 char *uri;
2598 char *pxid;
2599 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002600 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002601
2602 /* This is a first attempt at a better logging system.
2603 * For now, we rely on send_log() to provide the date, although it obviously
2604 * is the date of the log and not of the request, and most fields are not
2605 * computed.
2606 */
2607
willy tarreaua1598082005-12-17 13:08:06 +01002608 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002609
willy tarreau8a86dbf2005-12-18 00:45:59 +01002610 if (s->cli_addr.ss_family == AF_INET)
2611 inet_ntop(AF_INET,
2612 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2613 pn, sizeof(pn));
2614 else
2615 inet_ntop(AF_INET6,
2616 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2617 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002618
willy tarreauc1cae632005-12-17 14:12:23 +01002619 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002620 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002621 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002622
willy tarreauc1cae632005-12-17 14:12:23 +01002623 tm = localtime(&s->logs.tv_accept.tv_sec);
2624 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002625 char tmpline[MAX_SYSLOG_LEN], *h;
2626 int hdr;
2627
2628 h = tmpline;
2629 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2630 *(h++) = ' ';
2631 *(h++) = '{';
2632 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2633 if (hdr)
2634 *(h++) = '|';
2635 if (s->req_cap[hdr] != NULL)
2636 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2637 }
2638 *(h++) = '}';
2639 }
2640
2641 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2642 *(h++) = ' ';
2643 *(h++) = '{';
2644 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2645 if (hdr)
2646 *(h++) = '|';
2647 if (s->rsp_cap[hdr] != NULL)
2648 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2649 }
2650 *(h++) = '}';
2651 }
2652
2653 if (h < tmpline + sizeof(tmpline) - 4) {
2654 *(h++) = ' ';
2655 *(h++) = '"';
2656 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2657 *(h++) = '"';
2658 }
2659 *h = '\0';
2660
willy tarreauc1364612006-04-07 16:28:28 +02002661 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%s%d %d %s%lld %s %s %c%c%c%c %d/%d/%d%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002662 pn,
2663 (s->cli_addr.ss_family == AF_INET) ?
2664 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2665 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002666 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2667 tm->tm_hour, tm->tm_min, tm->tm_sec,
2668 pxid, srv,
2669 s->logs.t_request,
2670 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2671 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002672 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2673 s->logs.status,
2674 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002675 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2676 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002677 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2678 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2679 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2680 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreauc1364612006-04-07 16:28:28 +02002681 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002682 }
2683 else {
willy tarreauc1364612006-04-07 16:28:28 +02002684 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c %d/%d/%d\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002685 pn,
2686 (s->cli_addr.ss_family == AF_INET) ?
2687 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2688 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002689 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2690 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002691 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002692 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002693 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2694 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002695 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002696 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreauc1364612006-04-07 16:28:28 +02002697 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002698 }
2699
2700 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002701}
2702
willy tarreaue39cd132005-12-17 13:00:18 +01002703
2704/*
willy tarreau0f7af912005-12-17 12:21:26 +01002705 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002706 * to an accept. It tries to accept as many connections as possible.
2707 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002708 */
2709int event_accept(int fd) {
2710 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002711 struct session *s;
2712 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002713 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01002714 int max_accept;
2715
2716 if (global.nbproc > 1)
2717 max_accept = 8; /* let other processes catch some connections too */
2718 else
2719 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01002720
willy tarreauc2becdc2006-03-19 19:36:48 +01002721 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002722 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002723 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002724
willy tarreaub1285d52005-12-18 01:20:14 +01002725 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2726 switch (errno) {
2727 case EAGAIN:
2728 case EINTR:
2729 case ECONNABORTED:
2730 return 0; /* nothing more to accept */
2731 case ENFILE:
2732 send_log(p, LOG_EMERG,
2733 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2734 p->id, maxfd);
2735 return 0;
2736 case EMFILE:
2737 send_log(p, LOG_EMERG,
2738 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2739 p->id, maxfd);
2740 return 0;
2741 case ENOBUFS:
2742 case ENOMEM:
2743 send_log(p, LOG_EMERG,
2744 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2745 p->id, maxfd);
2746 return 0;
2747 default:
2748 return 0;
2749 }
2750 }
willy tarreau0f7af912005-12-17 12:21:26 +01002751
willy tarreau5cbea6f2005-12-17 12:48:26 +01002752 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2753 Alert("out of memory in event_accept().\n");
2754 FD_CLR(fd, StaticReadEvent);
2755 p->state = PR_STIDLE;
2756 close(cfd);
2757 return 0;
2758 }
willy tarreau0f7af912005-12-17 12:21:26 +01002759
willy tarreaub1285d52005-12-18 01:20:14 +01002760 /* if this session comes from a known monitoring system, we want to ignore
2761 * it as soon as possible, which means closing it immediately for TCP.
2762 */
2763 s->flags = 0;
2764 if (addr.ss_family == AF_INET &&
2765 p->mon_mask.s_addr &&
2766 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2767 if (p->mode == PR_MODE_TCP) {
2768 close(cfd);
2769 pool_free(session, s);
2770 continue;
2771 }
2772 s->flags |= SN_MONITOR;
2773 }
2774
willy tarreau5cbea6f2005-12-17 12:48:26 +01002775 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2776 Alert("out of memory in event_accept().\n");
2777 FD_CLR(fd, StaticReadEvent);
2778 p->state = PR_STIDLE;
2779 close(cfd);
2780 pool_free(session, s);
2781 return 0;
2782 }
willy tarreau0f7af912005-12-17 12:21:26 +01002783
willy tarreau5cbea6f2005-12-17 12:48:26 +01002784 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002785 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002786 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2787 close(cfd);
2788 pool_free(task, t);
2789 pool_free(session, s);
2790 return 0;
2791 }
willy tarreau0f7af912005-12-17 12:21:26 +01002792
willy tarreau5cbea6f2005-12-17 12:48:26 +01002793 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2794 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2795 (char *) &one, sizeof(one)) == -1)) {
2796 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2797 close(cfd);
2798 pool_free(task, t);
2799 pool_free(session, s);
2800 return 0;
2801 }
willy tarreau0f7af912005-12-17 12:21:26 +01002802
willy tarreaub952e1d2005-12-18 01:31:20 +01002803 if (p->options & PR_O_TCP_CLI_KA)
2804 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2805
willy tarreau9fe663a2005-12-17 13:02:59 +01002806 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2807 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2808 t->state = TASK_IDLE;
2809 t->process = process_session;
2810 t->context = s;
2811
2812 s->task = t;
2813 s->proxy = p;
2814 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2815 s->srv_state = SV_STIDLE;
2816 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002817
willy tarreau9fe663a2005-12-17 13:02:59 +01002818 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2819 s->cli_fd = cfd;
2820 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002821 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002822 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002823
willy tarreaub1285d52005-12-18 01:20:14 +01002824 if (s->flags & SN_MONITOR)
2825 s->logs.logwait = 0;
2826 else
2827 s->logs.logwait = p->to_log;
2828
willy tarreaua1598082005-12-17 13:08:06 +01002829 s->logs.tv_accept = now;
2830 s->logs.t_request = -1;
2831 s->logs.t_connect = -1;
2832 s->logs.t_data = -1;
2833 s->logs.t_close = 0;
2834 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002835 s->logs.cli_cookie = NULL;
2836 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002837 s->logs.status = -1;
2838 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002839
willy tarreau2f6ba652005-12-17 13:57:42 +01002840 s->uniq_id = totalconn;
willy tarreaub1c331f2006-04-07 18:23:29 +02002841 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01002842
willy tarreau4302f492005-12-18 01:00:37 +01002843 if (p->nb_req_cap > 0) {
2844 if ((s->req_cap =
2845 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2846 == NULL) { /* no memory */
2847 close(cfd); /* nothing can be done for this fd without memory */
2848 pool_free(task, t);
2849 pool_free(session, s);
2850 return 0;
2851 }
2852 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2853 }
2854 else
2855 s->req_cap = NULL;
2856
2857 if (p->nb_rsp_cap > 0) {
2858 if ((s->rsp_cap =
2859 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2860 == NULL) { /* no memory */
2861 if (s->req_cap != NULL)
2862 pool_free_to(p->req_cap_pool, s->req_cap);
2863 close(cfd); /* nothing can be done for this fd without memory */
2864 pool_free(task, t);
2865 pool_free(session, s);
2866 return 0;
2867 }
2868 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2869 }
2870 else
2871 s->rsp_cap = NULL;
2872
willy tarreau5cbea6f2005-12-17 12:48:26 +01002873 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2874 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002875 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002876 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002877
willy tarreau8a86dbf2005-12-18 00:45:59 +01002878 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002879 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002880 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002881 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002882
willy tarreau9fe663a2005-12-17 13:02:59 +01002883 if (p->to_log) {
2884 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002885 if (s->logs.logwait & LW_CLIP)
2886 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002887 sess_log(s);
2888 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002889 else if (s->cli_addr.ss_family == AF_INET) {
2890 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2891 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2892 sn, sizeof(sn)) &&
2893 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2894 pn, sizeof(pn))) {
2895 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2896 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2897 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2898 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2899 }
2900 }
2901 else {
2902 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2903 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2904 sn, sizeof(sn)) &&
2905 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2906 pn, sizeof(pn))) {
2907 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2908 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2909 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2910 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2911 }
2912 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002913 }
willy tarreau0f7af912005-12-17 12:21:26 +01002914
willy tarreau982249e2005-12-18 00:57:06 +01002915 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002916 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002917 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002918 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002919 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002920 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002921 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002922 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002923
willy tarreau8a86dbf2005-12-18 00:45:59 +01002924 if (s->cli_addr.ss_family == AF_INET) {
2925 char pn[INET_ADDRSTRLEN];
2926 inet_ntop(AF_INET,
2927 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2928 pn, sizeof(pn));
2929
2930 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2931 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2932 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2933 }
2934 else {
2935 char pn[INET6_ADDRSTRLEN];
2936 inet_ntop(AF_INET6,
2937 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2938 pn, sizeof(pn));
2939
2940 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2941 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2942 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2943 }
2944
willy tarreauef900ab2005-12-17 12:52:52 +01002945 write(1, trash, len);
2946 }
willy tarreau0f7af912005-12-17 12:21:26 +01002947
willy tarreau5cbea6f2005-12-17 12:48:26 +01002948 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002949 if (s->rsp_cap != NULL)
2950 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2951 if (s->req_cap != NULL)
2952 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002953 close(cfd); /* nothing can be done for this fd without memory */
2954 pool_free(task, t);
2955 pool_free(session, s);
2956 return 0;
2957 }
willy tarreau4302f492005-12-18 01:00:37 +01002958
willy tarreau5cbea6f2005-12-17 12:48:26 +01002959 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002960 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002961 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2962 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002963 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002964 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002965
willy tarreau5cbea6f2005-12-17 12:48:26 +01002966 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2967 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002968 if (s->rsp_cap != NULL)
2969 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2970 if (s->req_cap != NULL)
2971 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002972 close(cfd); /* nothing can be done for this fd without memory */
2973 pool_free(task, t);
2974 pool_free(session, s);
2975 return 0;
2976 }
2977 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002978 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002979 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 +01002980
willy tarreau5cbea6f2005-12-17 12:48:26 +01002981 fdtab[cfd].read = &event_cli_read;
2982 fdtab[cfd].write = &event_cli_write;
2983 fdtab[cfd].owner = t;
2984 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002985
willy tarreaub1285d52005-12-18 01:20:14 +01002986 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2987 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2988 /* Either we got a request from a monitoring system on an HTTP instance,
2989 * or we're in health check mode with the 'httpchk' option enabled. In
2990 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2991 */
2992 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2993 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2994 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002995 }
2996 else {
2997 FD_SET(cfd, StaticReadEvent);
2998 }
2999
willy tarreaub952e1d2005-12-18 01:31:20 +01003000#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3001 if (PrevReadEvent) {
3002 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3003 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3004 }
3005#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003006 fd_insert(cfd);
3007
3008 tv_eternity(&s->cnexpire);
3009 tv_eternity(&s->srexpire);
3010 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003011 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003012 tv_eternity(&s->cwexpire);
3013
willy tarreaub1285d52005-12-18 01:20:14 +01003014 if (s->proxy->clitimeout) {
3015 if (FD_ISSET(cfd, StaticReadEvent))
3016 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3017 if (FD_ISSET(cfd, StaticWriteEvent))
3018 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3019 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003020
willy tarreaub1285d52005-12-18 01:20:14 +01003021 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003022
3023 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003024
3025 if (p->mode != PR_MODE_HEALTH)
3026 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003027
3028 p->nbconn++;
3029 actconn++;
3030 totalconn++;
3031
willy tarreaub952e1d2005-12-18 01:31:20 +01003032 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003033 } /* end of while (p->nbconn < p->maxconn) */
3034 return 0;
3035}
willy tarreau0f7af912005-12-17 12:21:26 +01003036
willy tarreau0f7af912005-12-17 12:21:26 +01003037
willy tarreau5cbea6f2005-12-17 12:48:26 +01003038/*
3039 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003040 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3041 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003042 * or -1 if an error occured.
3043 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003044int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003045 struct task *t = fdtab[fd].owner;
3046 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003047 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003048 socklen_t lskerr = sizeof(skerr);
3049
willy tarreau05be12b2006-03-19 19:35:00 +01003050 skerr = 1;
3051 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3052 || (skerr != 0)) {
3053 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003054 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003055 fdtab[fd].state = FD_STERROR;
3056 FD_CLR(fd, StaticWriteEvent);
3057 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003058 else if (s->result != -1) {
3059 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003060 if (s->proxy->options & PR_O_HTTP_CHK) {
3061 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003062 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003063 * so we'll send the request, and won't wake the checker up now.
3064 */
3065#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003066 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003067#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003068 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003069#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003070 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003071 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3072 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3073 return 0;
3074 }
willy tarreau05be12b2006-03-19 19:35:00 +01003075 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003076 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003077 FD_CLR(fd, StaticWriteEvent);
3078 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003079 }
3080 else {
3081 /* good TCP connection is enough */
3082 s->result = 1;
3083 }
3084 }
3085
3086 task_wakeup(&rq, t);
3087 return 0;
3088}
3089
willy tarreau0f7af912005-12-17 12:21:26 +01003090
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003091/*
3092 * This function is used only for server health-checks. It handles
3093 * the server's reply to an HTTP request. It returns 1 if the server replies
3094 * 2xx or 3xx (valid responses), or -1 in other cases.
3095 */
3096int event_srv_chk_r(int fd) {
3097 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003098 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003099 struct task *t = fdtab[fd].owner;
3100 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003101 int skerr;
3102 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003103
willy tarreaua4a583a2005-12-18 01:39:19 +01003104 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003105
willy tarreau05be12b2006-03-19 19:35:00 +01003106 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3107 if (!skerr) {
3108#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003109 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003110#else
willy tarreau05be12b2006-03-19 19:35:00 +01003111 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3112 * but the connection was closed on the remote end. Fortunately, recv still
3113 * works correctly and we don't need to do the getsockopt() on linux.
3114 */
3115 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003116#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003117
3118 if ((len >= sizeof("HTTP/1.0 000")) &&
3119 !memcmp(reply, "HTTP/1.", 7) &&
3120 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3121 result = 1;
3122 }
3123
3124 if (result == -1)
3125 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003126
3127 if (s->result != -1)
3128 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003129
3130 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003131 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003132 return 0;
3133}
3134
3135
3136/*
3137 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3138 * and moves <end> just after the end of <str>.
3139 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3140 * the shift value (positive or negative) is returned.
3141 * If there's no space left, the move is not done.
3142 *
3143 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003144int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003145 int delta;
3146 int len;
3147
3148 len = strlen(str);
3149 delta = len - (end - pos);
3150
3151 if (delta + b->r >= b->data + BUFSIZE)
3152 return 0; /* no space left */
3153
3154 /* first, protect the end of the buffer */
3155 memmove(end + delta, end, b->data + b->l - end);
3156
3157 /* now, copy str over pos */
3158 memcpy(pos, str,len);
3159
willy tarreau5cbea6f2005-12-17 12:48:26 +01003160 /* we only move data after the displaced zone */
3161 if (b->r > pos) b->r += delta;
3162 if (b->w > pos) b->w += delta;
3163 if (b->h > pos) b->h += delta;
3164 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003165 b->l += delta;
3166
3167 return delta;
3168}
3169
willy tarreau8337c6b2005-12-17 13:41:01 +01003170/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003171 * len is 0.
3172 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003173int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003174 int delta;
3175
3176 delta = len - (end - pos);
3177
3178 if (delta + b->r >= b->data + BUFSIZE)
3179 return 0; /* no space left */
3180
Willy TARREAUe78ae262006-01-08 01:24:12 +01003181 if (b->data + b->l < end)
3182 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3183 return 0;
3184
willy tarreau0f7af912005-12-17 12:21:26 +01003185 /* first, protect the end of the buffer */
3186 memmove(end + delta, end, b->data + b->l - end);
3187
3188 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003189 if (len)
3190 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003191
willy tarreau5cbea6f2005-12-17 12:48:26 +01003192 /* we only move data after the displaced zone */
3193 if (b->r > pos) b->r += delta;
3194 if (b->w > pos) b->w += delta;
3195 if (b->h > pos) b->h += delta;
3196 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003197 b->l += delta;
3198
3199 return delta;
3200}
3201
3202
3203int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3204 char *old_dst = dst;
3205
3206 while (*str) {
3207 if (*str == '\\') {
3208 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003209 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003210 int len, num;
3211
3212 num = *str - '0';
3213 str++;
3214
willy tarreau8a86dbf2005-12-18 00:45:59 +01003215 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003216 len = matches[num].rm_eo - matches[num].rm_so;
3217 memcpy(dst, src + matches[num].rm_so, len);
3218 dst += len;
3219 }
3220
3221 }
3222 else if (*str == 'x') {
3223 unsigned char hex1, hex2;
3224 str++;
3225
willy tarreauc1f47532005-12-18 01:08:26 +01003226 hex1 = toupper(*str++) - '0';
3227 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003228
3229 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3230 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3231 *dst++ = (hex1<<4) + hex2;
3232 }
3233 else
3234 *dst++ = *str++;
3235 }
3236 else
3237 *dst++ = *str++;
3238 }
3239 *dst = 0;
3240 return dst - old_dst;
3241}
3242
willy tarreauc1f47532005-12-18 01:08:26 +01003243static int ishex(char s)
3244{
3245 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3246}
3247
3248/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3249char *check_replace_string(char *str)
3250{
3251 char *err = NULL;
3252 while (*str) {
3253 if (*str == '\\') {
3254 err = str; /* in case of a backslash, we return the pointer to it */
3255 str++;
3256 if (!*str)
3257 return err;
3258 else if (isdigit((int)*str))
3259 err = NULL;
3260 else if (*str == 'x') {
3261 str++;
3262 if (!ishex(*str))
3263 return err;
3264 str++;
3265 if (!ishex(*str))
3266 return err;
3267 err = NULL;
3268 }
3269 else {
3270 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3271 err = NULL;
3272 }
3273 }
3274 str++;
3275 }
3276 return err;
3277}
3278
3279
willy tarreau9fe663a2005-12-17 13:02:59 +01003280
willy tarreau0f7af912005-12-17 12:21:26 +01003281/*
3282 * manages the client FSM and its socket. BTW, it also tries to handle the
3283 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3284 * 0 else.
3285 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003286int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003287 int s = t->srv_state;
3288 int c = t->cli_state;
3289 struct buffer *req = t->req;
3290 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003291 int method_checked = 0;
3292 appsess *asession_temp = NULL;
3293 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003294
willy tarreau750a4722005-12-17 13:21:24 +01003295#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003296 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3297 cli_stnames[c], srv_stnames[s],
3298 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3299 t->crexpire.tv_sec, t->crexpire.tv_usec,
3300 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003301#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003302 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3303 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3304 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3305 //);
3306 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003307 /* now parse the partial (or complete) headers */
3308 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3309 char *ptr;
3310 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003311 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003312
willy tarreau5cbea6f2005-12-17 12:48:26 +01003313 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003314
willy tarreau0f7af912005-12-17 12:21:26 +01003315 /* look for the end of the current header */
3316 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3317 ptr++;
3318
willy tarreau5cbea6f2005-12-17 12:48:26 +01003319 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003320 int line, len;
3321 /* we can only get here after an end of headers */
3322 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003323
willy tarreaue39cd132005-12-17 13:00:18 +01003324 if (t->flags & SN_CLDENY) {
3325 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003326 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003327 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003328 if (!(t->flags & SN_ERR_MASK))
3329 t->flags |= SN_ERR_PRXCOND;
3330 if (!(t->flags & SN_FINST_MASK))
3331 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003332 return 1;
3333 }
3334
willy tarreau5cbea6f2005-12-17 12:48:26 +01003335 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003336 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3337 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003338 }
willy tarreau0f7af912005-12-17 12:21:26 +01003339
willy tarreau9fe663a2005-12-17 13:02:59 +01003340 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003341 if (t->cli_addr.ss_family == AF_INET) {
3342 unsigned char *pn;
3343 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3344 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3345 pn[0], pn[1], pn[2], pn[3]);
3346 buffer_replace2(req, req->h, req->h, trash, len);
3347 }
3348 else if (t->cli_addr.ss_family == AF_INET6) {
3349 char pn[INET6_ADDRSTRLEN];
3350 inet_ntop(AF_INET6,
3351 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3352 pn, sizeof(pn));
3353 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3354 buffer_replace2(req, req->h, req->h, trash, len);
3355 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003356 }
3357
willy tarreau25c4ea52005-12-18 00:49:49 +01003358 /* add a "connection: close" line if needed */
3359 if (t->proxy->options & PR_O_HTTP_CLOSE)
3360 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3361
willy tarreau982249e2005-12-18 00:57:06 +01003362 if (!memcmp(req->data, "POST ", 5)) {
3363 /* this is a POST request, which is not cacheable by default */
3364 t->flags |= SN_POST;
3365 }
willy tarreaucd878942005-12-17 13:27:43 +01003366
willy tarreau5cbea6f2005-12-17 12:48:26 +01003367 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003368 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003369
willy tarreau750a4722005-12-17 13:21:24 +01003370 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003371 /* FIXME: we'll set the client in a wait state while we try to
3372 * connect to the server. Is this really needed ? wouldn't it be
3373 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003374 //FD_CLR(t->cli_fd, StaticReadEvent);
3375 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003376
3377 /* FIXME: if we break here (as up to 1.1.23), having the client
3378 * shutdown its connection can lead to an abort further.
3379 * it's better to either return 1 or even jump directly to the
3380 * data state which will save one schedule.
3381 */
3382 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003383
3384 if (!t->proxy->clitimeout ||
3385 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3386 /* If the client has no timeout, or if the server is not ready yet,
3387 * and we know for sure that it can expire, then it's cleaner to
3388 * disable the timeout on the client side so that too low values
3389 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003390 *
3391 * FIXME-20050705: the server needs a way to re-enable this time-out
3392 * when it switches its state, otherwise a client can stay connected
3393 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003394 */
3395 tv_eternity(&t->crexpire);
3396
willy tarreau197e8ec2005-12-17 14:10:59 +01003397 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003398 }
willy tarreau0f7af912005-12-17 12:21:26 +01003399
Willy TARREAU13032e72006-03-12 17:31:45 +01003400 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3401 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003402 /* this is a partial header, let's wait for more to come */
3403 req->lr = ptr;
3404 break;
3405 }
willy tarreau0f7af912005-12-17 12:21:26 +01003406
willy tarreau5cbea6f2005-12-17 12:48:26 +01003407 /* now we know that *ptr is either \r or \n,
3408 * and that there are at least 1 char after it.
3409 */
3410 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3411 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3412 else
3413 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003414
willy tarreau5cbea6f2005-12-17 12:48:26 +01003415 /*
3416 * now we know that we have a full header ; we can do whatever
3417 * we want with these pointers :
3418 * req->h = beginning of header
3419 * ptr = end of header (first \r or \n)
3420 * req->lr = beginning of next line (next rep->h)
3421 * req->r = end of data (not used at this stage)
3422 */
willy tarreau0f7af912005-12-17 12:21:26 +01003423
willy tarreau12350152005-12-18 01:03:27 +01003424 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3425 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3426 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3427
3428 /* skip ; */
3429 request_line++;
3430
3431 /* look if we have a jsessionid */
3432
3433 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3434
3435 /* skip jsessionid= */
3436 request_line += t->proxy->appsession_name_len + 1;
3437
3438 /* First try if we allready have an appsession */
3439 asession_temp = &local_asession;
3440
3441 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3442 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3443 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3444 return 0;
3445 }
3446
3447 /* Copy the sessionid */
3448 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3449 asession_temp->sessid[t->proxy->appsession_len] = 0;
3450 asession_temp->serverid = NULL;
3451
3452 /* only do insert, if lookup fails */
3453 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3454 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3455 Alert("Not enough memory process_cli():asession:calloc().\n");
3456 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3457 return 0;
3458 }
3459 asession_temp->sessid = local_asession.sessid;
3460 asession_temp->serverid = local_asession.serverid;
3461 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003462 } /* end if (chtbl_lookup()) */
3463 else {
willy tarreau12350152005-12-18 01:03:27 +01003464 /*free wasted memory;*/
3465 pool_free_to(apools.sessid, local_asession.sessid);
3466 }
3467
3468 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3469 asession_temp->request_count++;
3470
3471#if defined(DEBUG_HASH)
3472 print_table(&(t->proxy->htbl_proxy));
3473#endif
3474
3475 if (asession_temp->serverid == NULL) {
3476 Alert("Found Application Session without matching server.\n");
3477 } else {
3478 struct server *srv = t->proxy->srv;
3479 while (srv) {
3480 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3481 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3482 /* we found the server and it's usable */
3483 t->flags &= ~SN_CK_MASK;
3484 t->flags |= SN_CK_VALID | SN_DIRECT;
3485 t->srv = srv;
3486 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003487 } else {
willy tarreau12350152005-12-18 01:03:27 +01003488 t->flags &= ~SN_CK_MASK;
3489 t->flags |= SN_CK_DOWN;
3490 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003491 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003492 srv = srv->next;
3493 }/* end while(srv) */
3494 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003495 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003496 else {
3497 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3498 }
willy tarreau598da412005-12-18 01:07:29 +01003499 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003500 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003501 else{
3502 //printf("No Methode-Header with Session-String\n");
3503 }
3504
willy tarreau8337c6b2005-12-17 13:41:01 +01003505 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003506 /* we have a complete HTTP request that we must log */
3507 int urilen;
3508
willy tarreaua1598082005-12-17 13:08:06 +01003509 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003510 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003511 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003512 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003513 if (!(t->flags & SN_ERR_MASK))
3514 t->flags |= SN_ERR_PRXCOND;
3515 if (!(t->flags & SN_FINST_MASK))
3516 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003517 return 1;
3518 }
3519
3520 urilen = ptr - req->h;
3521 if (urilen >= REQURI_LEN)
3522 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003523 memcpy(t->logs.uri, req->h, urilen);
3524 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003525
willy tarreaua1598082005-12-17 13:08:06 +01003526 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003527 sess_log(t);
3528 }
willy tarreau4302f492005-12-18 01:00:37 +01003529 else if (t->logs.logwait & LW_REQHDR) {
3530 struct cap_hdr *h;
3531 int len;
3532 for (h = t->proxy->req_cap; h; h = h->next) {
3533 if ((h->namelen + 2 <= ptr - req->h) &&
3534 (req->h[h->namelen] == ':') &&
3535 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3536
3537 if (t->req_cap[h->index] == NULL)
3538 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3539
3540 len = ptr - (req->h + h->namelen + 2);
3541 if (len > h->len)
3542 len = h->len;
3543
3544 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3545 t->req_cap[h->index][len]=0;
3546 }
3547 }
3548
3549 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003550
willy tarreau5cbea6f2005-12-17 12:48:26 +01003551 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003552
willy tarreau982249e2005-12-18 00:57:06 +01003553 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003554 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003555 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 +01003556 max = ptr - req->h;
3557 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003558 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003559 trash[len++] = '\n';
3560 write(1, trash, len);
3561 }
willy tarreau0f7af912005-12-17 12:21:26 +01003562
willy tarreau25c4ea52005-12-18 00:49:49 +01003563
3564 /* remove "connection: " if needed */
3565 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3566 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3567 delete_header = 1;
3568 }
3569
willy tarreau5cbea6f2005-12-17 12:48:26 +01003570 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003571 if (!delete_header && t->proxy->req_exp != NULL
3572 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003573 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003574 char term;
3575
3576 term = *ptr;
3577 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003578 exp = t->proxy->req_exp;
3579 do {
3580 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3581 switch (exp->action) {
3582 case ACT_ALLOW:
3583 if (!(t->flags & SN_CLDENY))
3584 t->flags |= SN_CLALLOW;
3585 break;
3586 case ACT_REPLACE:
3587 if (!(t->flags & SN_CLDENY)) {
3588 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3589 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3590 }
3591 break;
3592 case ACT_REMOVE:
3593 if (!(t->flags & SN_CLDENY))
3594 delete_header = 1;
3595 break;
3596 case ACT_DENY:
3597 if (!(t->flags & SN_CLALLOW))
3598 t->flags |= SN_CLDENY;
3599 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003600 case ACT_PASS: /* we simply don't deny this one */
3601 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003602 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003603 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003604 }
willy tarreaue39cd132005-12-17 13:00:18 +01003605 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003606 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003607 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003608
willy tarreau240afa62005-12-17 13:14:35 +01003609 /* Now look for cookies. Conforming to RFC2109, we have to support
3610 * attributes whose name begin with a '$', and associate them with
3611 * the right cookie, if we want to delete this cookie.
3612 * So there are 3 cases for each cookie read :
3613 * 1) it's a special attribute, beginning with a '$' : ignore it.
3614 * 2) it's a server id cookie that we *MAY* want to delete : save
3615 * some pointers on it (last semi-colon, beginning of cookie...)
3616 * 3) it's an application cookie : we *MAY* have to delete a previous
3617 * "special" cookie.
3618 * At the end of loop, if a "special" cookie remains, we may have to
3619 * remove it. If no application cookie persists in the header, we
3620 * *MUST* delete it
3621 */
willy tarreau12350152005-12-18 01:03:27 +01003622 if (!delete_header &&
3623 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003624 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003625 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003626 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003627 char *del_colon, *del_cookie, *colon;
3628 int app_cookies;
3629
willy tarreau5cbea6f2005-12-17 12:48:26 +01003630 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003631 colon = p1;
3632 /* del_cookie == NULL => nothing to be deleted */
3633 del_colon = del_cookie = NULL;
3634 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003635
3636 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003637 /* skip spaces and colons, but keep an eye on these ones */
3638 while (p1 < ptr) {
3639 if (*p1 == ';' || *p1 == ',')
3640 colon = p1;
3641 else if (!isspace((int)*p1))
3642 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003643 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003644 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003645
3646 if (p1 == ptr)
3647 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003648
3649 /* p1 is at the beginning of the cookie name */
3650 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003651 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003652 p2++;
3653
3654 if (p2 == ptr)
3655 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003656
3657 p3 = p2 + 1; /* skips the '=' sign */
3658 if (p3 == ptr)
3659 break;
3660
willy tarreau240afa62005-12-17 13:14:35 +01003661 p4 = p3;
3662 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003663 p4++;
3664
3665 /* here, we have the cookie name between p1 and p2,
3666 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003667 * we can process it :
3668 *
3669 * Cookie: NAME=VALUE;
3670 * | || || |
3671 * | || || +--> p4
3672 * | || |+-------> p3
3673 * | || +--------> p2
3674 * | |+------------> p1
3675 * | +-------------> colon
3676 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003677 */
3678
willy tarreau240afa62005-12-17 13:14:35 +01003679 if (*p1 == '$') {
3680 /* skip this one */
3681 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003682 else {
3683 /* first, let's see if we want to capture it */
3684 if (t->proxy->capture_name != NULL &&
3685 t->logs.cli_cookie == NULL &&
3686 (p4 - p1 >= t->proxy->capture_namelen) &&
3687 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3688 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003689
willy tarreau8337c6b2005-12-17 13:41:01 +01003690 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3691 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003692 } else {
3693 if (log_len > t->proxy->capture_len)
3694 log_len = t->proxy->capture_len;
3695 memcpy(t->logs.cli_cookie, p1, log_len);
3696 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003697 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003698 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003699
3700 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3701 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3702 /* Cool... it's the right one */
3703 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003704 char *delim;
3705
3706 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3707 * have the server ID betweek p3 and delim, and the original cookie between
3708 * delim+1 and p4. Otherwise, delim==p4 :
3709 *
3710 * Cookie: NAME=SRV~VALUE;
3711 * | || || | |
3712 * | || || | +--> p4
3713 * | || || +--------> delim
3714 * | || |+-----------> p3
3715 * | || +------------> p2
3716 * | |+----------------> p1
3717 * | +-----------------> colon
3718 * +------------------------> req->h
3719 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003720
willy tarreau0174f312005-12-18 01:02:42 +01003721 if (t->proxy->options & PR_O_COOK_PFX) {
3722 for (delim = p3; delim < p4; delim++)
3723 if (*delim == COOKIE_DELIM)
3724 break;
3725 }
3726 else
3727 delim = p4;
3728
3729
3730 /* Here, we'll look for the first running server which supports the cookie.
3731 * This allows to share a same cookie between several servers, for example
3732 * to dedicate backup servers to specific servers only.
3733 */
3734 while (srv) {
3735 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3736 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3737 /* we found the server and it's usable */
3738 t->flags &= ~SN_CK_MASK;
3739 t->flags |= SN_CK_VALID | SN_DIRECT;
3740 t->srv = srv;
3741 break;
willy tarreau12350152005-12-18 01:03:27 +01003742 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003743 /* we found a server, but it's down */
3744 t->flags &= ~SN_CK_MASK;
3745 t->flags |= SN_CK_DOWN;
3746 }
3747 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003748 srv = srv->next;
3749 }
3750
willy tarreau0174f312005-12-18 01:02:42 +01003751 if (!srv && !(t->flags & SN_CK_DOWN)) {
3752 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003753 t->flags &= ~SN_CK_MASK;
3754 t->flags |= SN_CK_INVALID;
3755 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003756
willy tarreau0174f312005-12-18 01:02:42 +01003757 /* depending on the cookie mode, we may have to either :
3758 * - delete the complete cookie if we're in insert+indirect mode, so that
3759 * the server never sees it ;
3760 * - remove the server id from the cookie value, and tag the cookie as an
3761 * application cookie so that it does not get accidentely removed later,
3762 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003763 */
willy tarreau0174f312005-12-18 01:02:42 +01003764 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3765 buffer_replace2(req, p3, delim + 1, NULL, 0);
3766 p4 -= (delim + 1 - p3);
3767 ptr -= (delim + 1 - p3);
3768 del_cookie = del_colon = NULL;
3769 app_cookies++; /* protect the header from deletion */
3770 }
3771 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003772 (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 +01003773 del_cookie = p1;
3774 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003775 }
willy tarreau12350152005-12-18 01:03:27 +01003776 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003777 /* now we know that we must keep this cookie since it's
3778 * not ours. But if we wanted to delete our cookie
3779 * earlier, we cannot remove the complete header, but we
3780 * can remove the previous block itself.
3781 */
3782 app_cookies++;
3783
3784 if (del_cookie != NULL) {
3785 buffer_replace2(req, del_cookie, p1, NULL, 0);
3786 p4 -= (p1 - del_cookie);
3787 ptr -= (p1 - del_cookie);
3788 del_cookie = del_colon = NULL;
3789 }
willy tarreau240afa62005-12-17 13:14:35 +01003790 }
willy tarreau12350152005-12-18 01:03:27 +01003791
3792 if ((t->proxy->appsession_name != NULL) &&
3793 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3794 /* first, let's see if the cookie is our appcookie*/
3795
3796 /* Cool... it's the right one */
3797
3798 asession_temp = &local_asession;
3799
3800 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3801 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3802 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3803 return 0;
3804 }
3805
3806 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3807 asession_temp->sessid[t->proxy->appsession_len] = 0;
3808 asession_temp->serverid = NULL;
3809
3810 /* only do insert, if lookup fails */
3811 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3812 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3813 Alert("Not enough memory process_cli():asession:calloc().\n");
3814 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3815 return 0;
3816 }
3817
3818 asession_temp->sessid = local_asession.sessid;
3819 asession_temp->serverid = local_asession.serverid;
3820 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3821 }
3822 else{
3823 /* free wasted memory */
3824 pool_free_to(apools.sessid, local_asession.sessid);
3825 }
3826
3827 if (asession_temp->serverid == NULL) {
3828 Alert("Found Application Session without matching server.\n");
3829 } else {
3830 struct server *srv = t->proxy->srv;
3831 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003832 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003833 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3834 /* we found the server and it's usable */
3835 t->flags &= ~SN_CK_MASK;
3836 t->flags |= SN_CK_VALID | SN_DIRECT;
3837 t->srv = srv;
3838 break;
3839 } else {
3840 t->flags &= ~SN_CK_MASK;
3841 t->flags |= SN_CK_DOWN;
3842 }
3843 }
3844 srv = srv->next;
3845 }/* end while(srv) */
3846 }/* end else if server == NULL */
3847
3848 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003849 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003850 }
willy tarreau240afa62005-12-17 13:14:35 +01003851
willy tarreau5cbea6f2005-12-17 12:48:26 +01003852 /* we'll have to look for another cookie ... */
3853 p1 = p4;
3854 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003855
3856 /* There's no more cookie on this line.
3857 * We may have marked the last one(s) for deletion.
3858 * We must do this now in two ways :
3859 * - if there is no app cookie, we simply delete the header ;
3860 * - if there are app cookies, we must delete the end of the
3861 * string properly, including the colon/semi-colon before
3862 * the cookie name.
3863 */
3864 if (del_cookie != NULL) {
3865 if (app_cookies) {
3866 buffer_replace2(req, del_colon, ptr, NULL, 0);
3867 /* WARNING! <ptr> becomes invalid for now. If some code
3868 * below needs to rely on it before the end of the global
3869 * header loop, we need to correct it with this code :
3870 * ptr = del_colon;
3871 */
3872 }
3873 else
3874 delete_header = 1;
3875 }
3876 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003877
3878 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003879 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003880 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003881 }
willy tarreau240afa62005-12-17 13:14:35 +01003882 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3883
willy tarreau5cbea6f2005-12-17 12:48:26 +01003884 req->h = req->lr;
3885 } /* while (req->lr < req->r) */
3886
3887 /* end of header processing (even if incomplete) */
3888
willy tarreauef900ab2005-12-17 12:52:52 +01003889 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3890 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3891 * full. We cannot loop here since event_cli_read will disable it only if
3892 * req->l == rlim-data
3893 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003894 FD_SET(t->cli_fd, StaticReadEvent);
3895 if (t->proxy->clitimeout)
3896 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3897 else
3898 tv_eternity(&t->crexpire);
3899 }
3900
willy tarreaue39cd132005-12-17 13:00:18 +01003901 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003902 * won't be able to free more later, so the session will never terminate.
3903 */
willy tarreaue39cd132005-12-17 13:00:18 +01003904 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003905 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003906 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003907 if (!(t->flags & SN_ERR_MASK))
3908 t->flags |= SN_ERR_PRXCOND;
3909 if (!(t->flags & SN_FINST_MASK))
3910 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003911 return 1;
3912 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003913 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003914 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003915 tv_eternity(&t->crexpire);
3916 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003917 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003918 if (!(t->flags & SN_ERR_MASK))
3919 t->flags |= SN_ERR_CLICL;
3920 if (!(t->flags & SN_FINST_MASK))
3921 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003922 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003923 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003924 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3925
3926 /* read timeout : give up with an error message.
3927 */
3928 t->logs.status = 408;
3929 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003930 if (!(t->flags & SN_ERR_MASK))
3931 t->flags |= SN_ERR_CLITO;
3932 if (!(t->flags & SN_FINST_MASK))
3933 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003934 return 1;
3935 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003936
3937 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003938 }
3939 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003940 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003941 /* FIXME: this error handling is partly buggy because we always report
3942 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3943 * or HEADER phase. BTW, it's not logical to expire the client while
3944 * we're waiting for the server to connect.
3945 */
willy tarreau0f7af912005-12-17 12:21:26 +01003946 /* read or write error */
3947 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003948 tv_eternity(&t->crexpire);
3949 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003950 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003951 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003952 if (!(t->flags & SN_ERR_MASK))
3953 t->flags |= SN_ERR_CLICL;
3954 if (!(t->flags & SN_FINST_MASK))
3955 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003956 return 1;
3957 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003958 /* last read, or end of server write */
3959 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003960 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003961 tv_eternity(&t->crexpire);
3962 shutdown(t->cli_fd, SHUT_RD);
3963 t->cli_state = CL_STSHUTR;
3964 return 1;
3965 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003966 /* last server read and buffer empty */
3967 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003968 FD_CLR(t->cli_fd, StaticWriteEvent);
3969 tv_eternity(&t->cwexpire);
3970 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003971 /* We must ensure that the read part is still alive when switching
3972 * to shutw */
3973 FD_SET(t->cli_fd, StaticReadEvent);
3974 if (t->proxy->clitimeout)
3975 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003976 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003977 //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 +01003978 return 1;
3979 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003980 /* read timeout */
3981 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3982 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003983 tv_eternity(&t->crexpire);
3984 shutdown(t->cli_fd, SHUT_RD);
3985 t->cli_state = CL_STSHUTR;
3986 if (!(t->flags & SN_ERR_MASK))
3987 t->flags |= SN_ERR_CLITO;
3988 if (!(t->flags & SN_FINST_MASK))
3989 t->flags |= SN_FINST_D;
3990 return 1;
3991 }
3992 /* write timeout */
3993 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3994 FD_CLR(t->cli_fd, StaticWriteEvent);
3995 tv_eternity(&t->cwexpire);
3996 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003997 /* We must ensure that the read part is still alive when switching
3998 * to shutw */
3999 FD_SET(t->cli_fd, StaticReadEvent);
4000 if (t->proxy->clitimeout)
4001 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4002
willy tarreau036e1ce2005-12-17 13:46:33 +01004003 t->cli_state = CL_STSHUTW;
4004 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004005 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01004006 if (!(t->flags & SN_FINST_MASK))
4007 t->flags |= SN_FINST_D;
4008 return 1;
4009 }
willy tarreau0f7af912005-12-17 12:21:26 +01004010
willy tarreauc58fc692005-12-17 14:13:08 +01004011 if (req->l >= req->rlim - req->data) {
4012 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004013 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004014 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004015 FD_CLR(t->cli_fd, StaticReadEvent);
4016 tv_eternity(&t->crexpire);
4017 }
4018 }
4019 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004020 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004021 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4022 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004023 if (!t->proxy->clitimeout ||
4024 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4025 /* If the client has no timeout, or if the server not ready yet, and we
4026 * know for sure that it can expire, then it's cleaner to disable the
4027 * timeout on the client side so that too low values cannot make the
4028 * sessions abort too early.
4029 */
willy tarreau0f7af912005-12-17 12:21:26 +01004030 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004031 else
4032 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004033 }
4034 }
4035
4036 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004037 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004038 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4039 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4040 tv_eternity(&t->cwexpire);
4041 }
4042 }
4043 else { /* buffer not empty */
4044 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4045 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004046 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004047 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004048 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4049 t->crexpire = t->cwexpire;
4050 }
willy tarreau0f7af912005-12-17 12:21:26 +01004051 else
4052 tv_eternity(&t->cwexpire);
4053 }
4054 }
4055 return 0; /* other cases change nothing */
4056 }
4057 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004058 if (t->res_cw == RES_ERROR) {
4059 tv_eternity(&t->cwexpire);
4060 fd_delete(t->cli_fd);
4061 t->cli_state = CL_STCLOSE;
4062 if (!(t->flags & SN_ERR_MASK))
4063 t->flags |= SN_ERR_CLICL;
4064 if (!(t->flags & SN_FINST_MASK))
4065 t->flags |= SN_FINST_D;
4066 return 1;
4067 }
4068 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004069 tv_eternity(&t->cwexpire);
4070 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004071 t->cli_state = CL_STCLOSE;
4072 return 1;
4073 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004074 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4075 tv_eternity(&t->cwexpire);
4076 fd_delete(t->cli_fd);
4077 t->cli_state = CL_STCLOSE;
4078 if (!(t->flags & SN_ERR_MASK))
4079 t->flags |= SN_ERR_CLITO;
4080 if (!(t->flags & SN_FINST_MASK))
4081 t->flags |= SN_FINST_D;
4082 return 1;
4083 }
willy tarreau0f7af912005-12-17 12:21:26 +01004084 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004085 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004086 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4087 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4088 tv_eternity(&t->cwexpire);
4089 }
4090 }
4091 else { /* buffer not empty */
4092 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4093 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004094 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004095 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004096 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4097 t->crexpire = t->cwexpire;
4098 }
willy tarreau0f7af912005-12-17 12:21:26 +01004099 else
4100 tv_eternity(&t->cwexpire);
4101 }
4102 }
4103 return 0;
4104 }
4105 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004106 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004107 tv_eternity(&t->crexpire);
4108 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004109 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004110 if (!(t->flags & SN_ERR_MASK))
4111 t->flags |= SN_ERR_CLICL;
4112 if (!(t->flags & SN_FINST_MASK))
4113 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004114 return 1;
4115 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004116 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4117 tv_eternity(&t->crexpire);
4118 fd_delete(t->cli_fd);
4119 t->cli_state = CL_STCLOSE;
4120 return 1;
4121 }
4122 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4123 tv_eternity(&t->crexpire);
4124 fd_delete(t->cli_fd);
4125 t->cli_state = CL_STCLOSE;
4126 if (!(t->flags & SN_ERR_MASK))
4127 t->flags |= SN_ERR_CLITO;
4128 if (!(t->flags & SN_FINST_MASK))
4129 t->flags |= SN_FINST_D;
4130 return 1;
4131 }
willy tarreauef900ab2005-12-17 12:52:52 +01004132 else if (req->l >= req->rlim - req->data) {
4133 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004134
4135 /* FIXME-20050705: is it possible for a client to maintain a session
4136 * after the timeout by sending more data after it receives a close ?
4137 */
4138
willy tarreau0f7af912005-12-17 12:21:26 +01004139 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004140 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004141 FD_CLR(t->cli_fd, StaticReadEvent);
4142 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004143 //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 +01004144 }
4145 }
4146 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004147 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004148 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4149 FD_SET(t->cli_fd, StaticReadEvent);
4150 if (t->proxy->clitimeout)
4151 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4152 else
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 return 0;
4158 }
4159 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004160 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004161 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004162 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 +01004163 write(1, trash, len);
4164 }
4165 return 0;
4166 }
4167 return 0;
4168}
4169
4170
4171/*
4172 * manages the server FSM and its socket. It returns 1 if a state has changed
4173 * (and a resync may be needed), 0 else.
4174 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004175int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004176 int s = t->srv_state;
4177 int c = t->cli_state;
4178 struct buffer *req = t->req;
4179 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004180 appsess *asession_temp = NULL;
4181 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004182 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004183
willy tarreau750a4722005-12-17 13:21:24 +01004184#ifdef DEBUG_FULL
4185 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4186#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004187 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4188 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4189 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4190 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004191 if (s == SV_STIDLE) {
4192 if (c == CL_STHEADERS)
4193 return 0; /* stay in idle, waiting for data to reach the client side */
4194 else if (c == CL_STCLOSE ||
4195 c == CL_STSHUTW ||
4196 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4197 tv_eternity(&t->cnexpire);
4198 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004199 if (!(t->flags & SN_ERR_MASK))
4200 t->flags |= SN_ERR_CLICL;
4201 if (!(t->flags & SN_FINST_MASK))
4202 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004203 return 1;
4204 }
4205 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01004206 /* initiate a connection to the server */
4207 conn_err = connect_server(t);
4208 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004209 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4210 t->srv_state = SV_STCONN;
4211 }
4212 else { /* try again */
4213 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004214 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004215 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004216 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004217 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4218 t->flags &= ~SN_CK_MASK;
4219 t->flags |= SN_CK_DOWN;
4220 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004221 }
4222
willy tarreaub1285d52005-12-18 01:20:14 +01004223 conn_err = connect_server(t);
4224 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004225 t->srv_state = SV_STCONN;
4226 break;
4227 }
4228 }
4229 if (t->conn_retries < 0) {
4230 /* if conn_retries < 0 or other error, let's abort */
4231 tv_eternity(&t->cnexpire);
4232 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004233 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004234 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004235 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004236 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004237 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004238 if (!(t->flags & SN_FINST_MASK))
4239 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004240 }
4241 }
4242 return 1;
4243 }
4244 }
4245 else if (s == SV_STCONN) { /* connection in progress */
4246 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004247 //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 +01004248 return 0; /* nothing changed */
4249 }
4250 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4251 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4252 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004253 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004254 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004255 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004256 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004257 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004258 if (t->conn_retries >= 0) {
4259 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004260 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004261 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004262 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4263 t->flags &= ~SN_CK_MASK;
4264 t->flags |= SN_CK_DOWN;
4265 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004266 }
willy tarreaub1285d52005-12-18 01:20:14 +01004267 conn_err = connect_server(t);
4268 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004269 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004270 }
willy tarreaub1285d52005-12-18 01:20:14 +01004271 else if (t->res_sw == RES_SILENT)
4272 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4273 else
4274 conn_err = SN_ERR_SRVCL; // it was a connect error.
4275
willy tarreau0f7af912005-12-17 12:21:26 +01004276 /* if conn_retries < 0 or other error, let's abort */
4277 tv_eternity(&t->cnexpire);
4278 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004279 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004280 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004281 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004282 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004283 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004284 if (!(t->flags & SN_FINST_MASK))
4285 t->flags |= SN_FINST_C;
willy tarreau704f32b2006-04-07 17:37:55 +02004286 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01004287 return 1;
4288 }
4289 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004290 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004291
willy tarreau0f7af912005-12-17 12:21:26 +01004292 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004293 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004294 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004295 tv_eternity(&t->swexpire);
4296 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004297 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004298 if (t->proxy->srvtimeout) {
4299 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4300 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4301 t->srexpire = t->swexpire;
4302 }
4303 else
4304 tv_eternity(&t->swexpire);
4305 }
willy tarreau0f7af912005-12-17 12:21:26 +01004306
4307 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4308 FD_SET(t->srv_fd, StaticReadEvent);
4309 if (t->proxy->srvtimeout)
4310 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4311 else
4312 tv_eternity(&t->srexpire);
4313
4314 t->srv_state = SV_STDATA;
willy tarreaub1c331f2006-04-07 18:23:29 +02004315 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004316 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004317
4318 /* if the user wants to log as soon as possible, without counting
4319 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004320 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004321 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4322 sess_log(t);
4323 }
willy tarreau0f7af912005-12-17 12:21:26 +01004324 }
willy tarreauef900ab2005-12-17 12:52:52 +01004325 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004326 t->srv_state = SV_STHEADERS;
willy tarreaub1c331f2006-04-07 18:23:29 +02004327 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004328 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4329 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004330 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004331 return 1;
4332 }
4333 }
4334 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004335 /* now parse the partial (or complete) headers */
4336 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4337 char *ptr;
4338 int delete_header;
4339
4340 ptr = rep->lr;
4341
4342 /* look for the end of the current header */
4343 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4344 ptr++;
4345
4346 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004347 int line, len;
4348
4349 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004350
4351 /* first, we'll block if security checks have caught nasty things */
4352 if (t->flags & SN_CACHEABLE) {
4353 if ((t->flags & SN_CACHE_COOK) &&
4354 (t->flags & SN_SCK_ANY) &&
4355 (t->proxy->options & PR_O_CHK_CACHE)) {
4356
4357 /* we're in presence of a cacheable response containing
4358 * a set-cookie header. We'll block it as requested by
4359 * the 'checkcache' option, and send an alert.
4360 */
4361 tv_eternity(&t->srexpire);
4362 tv_eternity(&t->swexpire);
4363 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004364 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01004365 t->srv_state = SV_STCLOSE;
4366 t->logs.status = 502;
4367 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4368 if (!(t->flags & SN_ERR_MASK))
4369 t->flags |= SN_ERR_PRXCOND;
4370 if (!(t->flags & SN_FINST_MASK))
4371 t->flags |= SN_FINST_H;
4372
4373 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4374 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4375
willy tarreau704f32b2006-04-07 17:37:55 +02004376 /* TODO : check if there are pending connections on this server */
willy tarreau97f58572005-12-18 00:53:44 +01004377 return 1;
4378 }
4379 }
4380
willy tarreau982249e2005-12-18 00:57:06 +01004381 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4382 if (t->flags & SN_SVDENY) {
4383 tv_eternity(&t->srexpire);
4384 tv_eternity(&t->swexpire);
4385 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004386 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01004387 t->srv_state = SV_STCLOSE;
4388 t->logs.status = 502;
4389 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4390 if (!(t->flags & SN_ERR_MASK))
4391 t->flags |= SN_ERR_PRXCOND;
4392 if (!(t->flags & SN_FINST_MASK))
4393 t->flags |= SN_FINST_H;
willy tarreau704f32b2006-04-07 17:37:55 +02004394 /* TODO : check if there are pending connections on this server */
willy tarreau982249e2005-12-18 00:57:06 +01004395 return 1;
4396 }
4397
willy tarreau5cbea6f2005-12-17 12:48:26 +01004398 /* we'll have something else to do here : add new headers ... */
4399
willy tarreaucd878942005-12-17 13:27:43 +01004400 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4401 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004402 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004403 * insert a set-cookie here, except if we want to insert only on POST
4404 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004405 */
willy tarreau750a4722005-12-17 13:21:24 +01004406 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004407 t->proxy->cookie_name,
4408 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004409
willy tarreau036e1ce2005-12-17 13:46:33 +01004410 t->flags |= SN_SCK_INSERTED;
4411
willy tarreau750a4722005-12-17 13:21:24 +01004412 /* Here, we will tell an eventual cache on the client side that we don't
4413 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4414 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4415 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4416 */
willy tarreau240afa62005-12-17 13:14:35 +01004417 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004418 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4419 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004420
4421 if (rep->data + rep->l < rep->h)
4422 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4423 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004424 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004425 }
4426
4427 /* headers to be added */
4428 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004429 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4430 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004431 }
4432
willy tarreau25c4ea52005-12-18 00:49:49 +01004433 /* add a "connection: close" line if needed */
4434 if (t->proxy->options & PR_O_HTTP_CLOSE)
4435 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4436
willy tarreau5cbea6f2005-12-17 12:48:26 +01004437 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004438 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004439 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004440
Willy TARREAU767ba712006-03-01 22:40:50 +01004441 /* client connection already closed or option 'httpclose' required :
4442 * we close the server's outgoing connection right now.
4443 */
4444 if ((req->l == 0) &&
4445 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4446 FD_CLR(t->srv_fd, StaticWriteEvent);
4447 tv_eternity(&t->swexpire);
4448
4449 /* We must ensure that the read part is still alive when switching
4450 * to shutw */
4451 FD_SET(t->srv_fd, StaticReadEvent);
4452 if (t->proxy->srvtimeout)
4453 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4454
4455 shutdown(t->srv_fd, SHUT_WR);
4456 t->srv_state = SV_STSHUTW;
4457 }
4458
willy tarreau25c4ea52005-12-18 00:49:49 +01004459 /* if the user wants to log as soon as possible, without counting
4460 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004461 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004462 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4463 t->logs.bytes = rep->h - rep->data;
4464 sess_log(t);
4465 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004466 break;
4467 }
4468
4469 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4470 if (ptr > rep->r - 2) {
4471 /* this is a partial header, let's wait for more to come */
4472 rep->lr = ptr;
4473 break;
4474 }
4475
4476 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4477 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4478
4479 /* now we know that *ptr is either \r or \n,
4480 * and that there are at least 1 char after it.
4481 */
4482 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4483 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4484 else
4485 rep->lr = ptr + 2; /* \r\n or \n\r */
4486
4487 /*
4488 * now we know that we have a full header ; we can do whatever
4489 * we want with these pointers :
4490 * rep->h = beginning of header
4491 * ptr = end of header (first \r or \n)
4492 * rep->lr = beginning of next line (next rep->h)
4493 * rep->r = end of data (not used at this stage)
4494 */
4495
willy tarreaua1598082005-12-17 13:08:06 +01004496
willy tarreau982249e2005-12-18 00:57:06 +01004497 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004498 t->logs.logwait &= ~LW_RESP;
4499 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004500 switch (t->logs.status) {
4501 case 200:
4502 case 203:
4503 case 206:
4504 case 300:
4505 case 301:
4506 case 410:
4507 /* RFC2616 @13.4:
4508 * "A response received with a status code of
4509 * 200, 203, 206, 300, 301 or 410 MAY be stored
4510 * by a cache (...) unless a cache-control
4511 * directive prohibits caching."
4512 *
4513 * RFC2616 @9.5: POST method :
4514 * "Responses to this method are not cacheable,
4515 * unless the response includes appropriate
4516 * Cache-Control or Expires header fields."
4517 */
4518 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4519 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4520 break;
4521 default:
4522 break;
4523 }
willy tarreau4302f492005-12-18 01:00:37 +01004524 }
4525 else if (t->logs.logwait & LW_RSPHDR) {
4526 struct cap_hdr *h;
4527 int len;
4528 for (h = t->proxy->rsp_cap; h; h = h->next) {
4529 if ((h->namelen + 2 <= ptr - rep->h) &&
4530 (rep->h[h->namelen] == ':') &&
4531 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4532
4533 if (t->rsp_cap[h->index] == NULL)
4534 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4535
4536 len = ptr - (rep->h + h->namelen + 2);
4537 if (len > h->len)
4538 len = h->len;
4539
4540 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4541 t->rsp_cap[h->index][len]=0;
4542 }
4543 }
4544
willy tarreaua1598082005-12-17 13:08:06 +01004545 }
4546
willy tarreau5cbea6f2005-12-17 12:48:26 +01004547 delete_header = 0;
4548
willy tarreau982249e2005-12-18 00:57:06 +01004549 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004550 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004551 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 +01004552 max = ptr - rep->h;
4553 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004554 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004555 trash[len++] = '\n';
4556 write(1, trash, len);
4557 }
4558
willy tarreau25c4ea52005-12-18 00:49:49 +01004559 /* remove "connection: " if needed */
4560 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4561 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4562 delete_header = 1;
4563 }
4564
willy tarreau5cbea6f2005-12-17 12:48:26 +01004565 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004566 if (!delete_header && t->proxy->rsp_exp != NULL
4567 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004568 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004569 char term;
4570
4571 term = *ptr;
4572 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004573 exp = t->proxy->rsp_exp;
4574 do {
4575 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4576 switch (exp->action) {
4577 case ACT_ALLOW:
4578 if (!(t->flags & SN_SVDENY))
4579 t->flags |= SN_SVALLOW;
4580 break;
4581 case ACT_REPLACE:
4582 if (!(t->flags & SN_SVDENY)) {
4583 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4584 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4585 }
4586 break;
4587 case ACT_REMOVE:
4588 if (!(t->flags & SN_SVDENY))
4589 delete_header = 1;
4590 break;
4591 case ACT_DENY:
4592 if (!(t->flags & SN_SVALLOW))
4593 t->flags |= SN_SVDENY;
4594 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004595 case ACT_PASS: /* we simply don't deny this one */
4596 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004597 }
4598 break;
4599 }
willy tarreaue39cd132005-12-17 13:00:18 +01004600 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004601 *ptr = term; /* restore the string terminator */
4602 }
4603
willy tarreau97f58572005-12-18 00:53:44 +01004604 /* check for cache-control: or pragma: headers */
4605 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4606 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4607 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4608 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4609 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004610 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004611 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4612 else {
4613 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004614 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004615 t->flags &= ~SN_CACHE_COOK;
4616 }
4617 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004618 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004619 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004620 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004621 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4622 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004623 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004624 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004625 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4626 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4627 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4628 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4629 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4630 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004631 }
4632 }
4633 }
4634
willy tarreau5cbea6f2005-12-17 12:48:26 +01004635 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004636 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004637 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004638 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004639 char *p1, *p2, *p3, *p4;
4640
willy tarreau97f58572005-12-18 00:53:44 +01004641 t->flags |= SN_SCK_ANY;
4642
willy tarreau5cbea6f2005-12-17 12:48:26 +01004643 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4644
4645 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004646 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004647 p1++;
4648
4649 if (p1 == ptr || *p1 == ';') /* end of cookie */
4650 break;
4651
4652 /* p1 is at the beginning of the cookie name */
4653 p2 = p1;
4654
4655 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4656 p2++;
4657
4658 if (p2 == ptr || *p2 == ';') /* next cookie */
4659 break;
4660
4661 p3 = p2 + 1; /* skips the '=' sign */
4662 if (p3 == ptr)
4663 break;
4664
4665 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004666 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004667 p4++;
4668
4669 /* here, we have the cookie name between p1 and p2,
4670 * and its value between p3 and p4.
4671 * we can process it.
4672 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004673
4674 /* first, let's see if we want to capture it */
4675 if (t->proxy->capture_name != NULL &&
4676 t->logs.srv_cookie == NULL &&
4677 (p4 - p1 >= t->proxy->capture_namelen) &&
4678 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4679 int log_len = p4 - p1;
4680
4681 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4682 Alert("HTTP logging : out of memory.\n");
4683 }
4684
4685 if (log_len > t->proxy->capture_len)
4686 log_len = t->proxy->capture_len;
4687 memcpy(t->logs.srv_cookie, p1, log_len);
4688 t->logs.srv_cookie[log_len] = 0;
4689 }
4690
4691 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4692 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004693 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004694 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004695
4696 /* If the cookie is in insert mode on a known server, we'll delete
4697 * this occurrence because we'll insert another one later.
4698 * We'll delete it too if the "indirect" option is set and we're in
4699 * a direct access. */
4700 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004701 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004702 /* this header must be deleted */
4703 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004704 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004705 }
4706 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4707 /* replace bytes p3->p4 with the cookie name associated
4708 * with this server since we know it.
4709 */
4710 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004711 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004712 }
willy tarreau0174f312005-12-18 01:02:42 +01004713 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4714 /* insert the cookie name associated with this server
4715 * before existing cookie, and insert a delimitor between them..
4716 */
4717 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4718 p3[t->srv->cklen] = COOKIE_DELIM;
4719 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4720 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004721 break;
4722 }
willy tarreau12350152005-12-18 01:03:27 +01004723
4724 /* first, let's see if the cookie is our appcookie*/
4725 if ((t->proxy->appsession_name != NULL) &&
4726 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4727
4728 /* Cool... it's the right one */
4729
willy tarreaub952e1d2005-12-18 01:31:20 +01004730 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004731 asession_temp = &local_asession;
4732
willy tarreaub952e1d2005-12-18 01:31:20 +01004733 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004734 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4735 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4736 }
4737 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4738 asession_temp->sessid[t->proxy->appsession_len] = 0;
4739 asession_temp->serverid = NULL;
4740
4741 /* only do insert, if lookup fails */
4742 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4743 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4744 Alert("Not enought Memory process_srv():asession:calloc().\n");
4745 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4746 return 0;
4747 }
4748 asession_temp->sessid = local_asession.sessid;
4749 asession_temp->serverid = local_asession.serverid;
4750 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004751 }/* end if (chtbl_lookup()) */
4752 else {
willy tarreau12350152005-12-18 01:03:27 +01004753 /* free wasted memory */
4754 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004755 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004756
willy tarreaub952e1d2005-12-18 01:31:20 +01004757 if (asession_temp->serverid == NULL) {
4758 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004759 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4760 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4761 }
4762 asession_temp->serverid[0] = '\0';
4763 }
4764
willy tarreaub952e1d2005-12-18 01:31:20 +01004765 if (asession_temp->serverid[0] == '\0')
4766 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004767
4768 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4769
4770#if defined(DEBUG_HASH)
4771 print_table(&(t->proxy->htbl_proxy));
4772#endif
4773 break;
4774 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004775 else {
4776 // fprintf(stderr,"Ignoring unknown cookie : ");
4777 // write(2, p1, p2-p1);
4778 // fprintf(stderr," = ");
4779 // write(2, p3, p4-p3);
4780 // fprintf(stderr,"\n");
4781 }
4782 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4783 } /* we're now at the end of the cookie value */
4784 } /* end of cookie processing */
4785
willy tarreau97f58572005-12-18 00:53:44 +01004786 /* check for any set-cookie in case we check for cacheability */
4787 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4788 (t->proxy->options & PR_O_CHK_CACHE) &&
4789 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4790 t->flags |= SN_SCK_ANY;
4791 }
4792
willy tarreau5cbea6f2005-12-17 12:48:26 +01004793 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004794 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004795 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004796
willy tarreau5cbea6f2005-12-17 12:48:26 +01004797 rep->h = rep->lr;
4798 } /* while (rep->lr < rep->r) */
4799
4800 /* end of header processing (even if incomplete) */
4801
willy tarreauef900ab2005-12-17 12:52:52 +01004802 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4803 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4804 * full. We cannot loop here since event_srv_read will disable it only if
4805 * rep->l == rlim-data
4806 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004807 FD_SET(t->srv_fd, StaticReadEvent);
4808 if (t->proxy->srvtimeout)
4809 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4810 else
4811 tv_eternity(&t->srexpire);
4812 }
willy tarreau0f7af912005-12-17 12:21:26 +01004813
willy tarreau8337c6b2005-12-17 13:41:01 +01004814 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004815 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004816 tv_eternity(&t->srexpire);
4817 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004818 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004819 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01004820 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004821 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004822 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004823 if (!(t->flags & SN_ERR_MASK))
4824 t->flags |= SN_ERR_SRVCL;
4825 if (!(t->flags & SN_FINST_MASK))
4826 t->flags |= SN_FINST_H;
willy tarreau704f32b2006-04-07 17:37:55 +02004827 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01004828 return 1;
4829 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004830 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004831 * since we are in header mode, if there's no space left for headers, we
4832 * won't be able to free more later, so the session will never terminate.
4833 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004834 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 +01004835 FD_CLR(t->srv_fd, StaticReadEvent);
4836 tv_eternity(&t->srexpire);
4837 shutdown(t->srv_fd, SHUT_RD);
4838 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004839 //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 +01004840 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004841 }
4842 /* read timeout : return a 504 to the client.
4843 */
4844 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4845 tv_eternity(&t->srexpire);
4846 tv_eternity(&t->swexpire);
4847 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004848 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01004849 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 tarreau704f32b2006-04-07 17:37:55 +02004856 /* TODO : check if there are pending connections on this server */
willy tarreau8337c6b2005-12-17 13:41:01 +01004857 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004858 }
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 tarreauc1364612006-04-07 16:28:28 +02004943 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01004944 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004945 if (!(t->flags & SN_ERR_MASK))
4946 t->flags |= SN_ERR_SRVCL;
4947 if (!(t->flags & SN_FINST_MASK))
4948 t->flags |= SN_FINST_D;
willy tarreau704f32b2006-04-07 17:37:55 +02004949 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01004950 return 1;
4951 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004952 /* last read, or end of client write */
4953 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004954 FD_CLR(t->srv_fd, StaticReadEvent);
4955 tv_eternity(&t->srexpire);
4956 shutdown(t->srv_fd, SHUT_RD);
4957 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004958 //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 +01004959 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004960 }
4961 /* end of client read and no more data to send */
4962 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4963 FD_CLR(t->srv_fd, StaticWriteEvent);
4964 tv_eternity(&t->swexpire);
4965 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004966 /* We must ensure that the read part is still alive when switching
4967 * to shutw */
4968 FD_SET(t->srv_fd, StaticReadEvent);
4969 if (t->proxy->srvtimeout)
4970 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4971
willy tarreaua41a8b42005-12-17 14:02:24 +01004972 t->srv_state = SV_STSHUTW;
4973 return 1;
4974 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004975 /* read timeout */
4976 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4977 FD_CLR(t->srv_fd, StaticReadEvent);
4978 tv_eternity(&t->srexpire);
4979 shutdown(t->srv_fd, SHUT_RD);
4980 t->srv_state = SV_STSHUTR;
4981 if (!(t->flags & SN_ERR_MASK))
4982 t->flags |= SN_ERR_SRVTO;
4983 if (!(t->flags & SN_FINST_MASK))
4984 t->flags |= SN_FINST_D;
4985 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004986 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004987 /* write timeout */
4988 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004989 FD_CLR(t->srv_fd, StaticWriteEvent);
4990 tv_eternity(&t->swexpire);
4991 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004992 /* We must ensure that the read part is still alive when switching
4993 * to shutw */
4994 FD_SET(t->srv_fd, StaticReadEvent);
4995 if (t->proxy->srvtimeout)
4996 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004997 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004998 if (!(t->flags & SN_ERR_MASK))
4999 t->flags |= SN_ERR_SRVTO;
5000 if (!(t->flags & SN_FINST_MASK))
5001 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005002 return 1;
5003 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005004
5005 /* recompute request time-outs */
5006 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005007 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5008 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5009 tv_eternity(&t->swexpire);
5010 }
5011 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005012 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01005013 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5014 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005015 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005016 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005017 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5018 t->srexpire = t->swexpire;
5019 }
willy tarreau0f7af912005-12-17 12:21:26 +01005020 else
5021 tv_eternity(&t->swexpire);
5022 }
5023 }
5024
willy tarreaub1ff9db2005-12-17 13:51:03 +01005025 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01005026 if (rep->l == BUFSIZE) { /* no room to read more data */
5027 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5028 FD_CLR(t->srv_fd, StaticReadEvent);
5029 tv_eternity(&t->srexpire);
5030 }
5031 }
5032 else {
5033 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5034 FD_SET(t->srv_fd, StaticReadEvent);
5035 if (t->proxy->srvtimeout)
5036 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5037 else
5038 tv_eternity(&t->srexpire);
5039 }
5040 }
5041
5042 return 0; /* other cases change nothing */
5043 }
5044 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005045 if (t->res_sw == RES_ERROR) {
5046 //FD_CLR(t->srv_fd, StaticWriteEvent);
5047 tv_eternity(&t->swexpire);
5048 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005049 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005050 //close(t->srv_fd);
5051 t->srv_state = SV_STCLOSE;
5052 if (!(t->flags & SN_ERR_MASK))
5053 t->flags |= SN_ERR_SRVCL;
5054 if (!(t->flags & SN_FINST_MASK))
5055 t->flags |= SN_FINST_D;
willy tarreau704f32b2006-04-07 17:37:55 +02005056 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005057 return 1;
5058 }
5059 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005060 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005061 tv_eternity(&t->swexpire);
5062 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005063 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005064 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005065 t->srv_state = SV_STCLOSE;
willy tarreau704f32b2006-04-07 17:37:55 +02005066 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01005067 return 1;
5068 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005069 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5070 //FD_CLR(t->srv_fd, StaticWriteEvent);
5071 tv_eternity(&t->swexpire);
5072 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005073 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005074 //close(t->srv_fd);
5075 t->srv_state = SV_STCLOSE;
5076 if (!(t->flags & SN_ERR_MASK))
5077 t->flags |= SN_ERR_SRVTO;
5078 if (!(t->flags & SN_FINST_MASK))
5079 t->flags |= SN_FINST_D;
willy tarreau704f32b2006-04-07 17:37:55 +02005080 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005081 return 1;
5082 }
willy tarreau0f7af912005-12-17 12:21:26 +01005083 else if (req->l == 0) {
5084 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5085 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5086 tv_eternity(&t->swexpire);
5087 }
5088 }
5089 else { /* buffer not empty */
5090 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5091 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005092 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005093 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005094 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5095 t->srexpire = t->swexpire;
5096 }
willy tarreau0f7af912005-12-17 12:21:26 +01005097 else
5098 tv_eternity(&t->swexpire);
5099 }
5100 }
5101 return 0;
5102 }
5103 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005104 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005105 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005106 tv_eternity(&t->srexpire);
5107 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005108 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005109 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005110 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005111 if (!(t->flags & SN_ERR_MASK))
5112 t->flags |= SN_ERR_SRVCL;
5113 if (!(t->flags & SN_FINST_MASK))
5114 t->flags |= SN_FINST_D;
willy tarreau704f32b2006-04-07 17:37:55 +02005115 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01005116 return 1;
5117 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005118 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5119 //FD_CLR(t->srv_fd, StaticReadEvent);
5120 tv_eternity(&t->srexpire);
5121 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005122 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005123 //close(t->srv_fd);
5124 t->srv_state = SV_STCLOSE;
willy tarreau704f32b2006-04-07 17:37:55 +02005125 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005126 return 1;
5127 }
5128 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5129 //FD_CLR(t->srv_fd, StaticReadEvent);
5130 tv_eternity(&t->srexpire);
5131 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005132 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005133 //close(t->srv_fd);
5134 t->srv_state = SV_STCLOSE;
5135 if (!(t->flags & SN_ERR_MASK))
5136 t->flags |= SN_ERR_SRVTO;
5137 if (!(t->flags & SN_FINST_MASK))
5138 t->flags |= SN_FINST_D;
willy tarreau704f32b2006-04-07 17:37:55 +02005139 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005140 return 1;
5141 }
willy tarreau0f7af912005-12-17 12:21:26 +01005142 else if (rep->l == BUFSIZE) { /* no room to read more data */
5143 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5144 FD_CLR(t->srv_fd, StaticReadEvent);
5145 tv_eternity(&t->srexpire);
5146 }
5147 }
5148 else {
5149 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5150 FD_SET(t->srv_fd, StaticReadEvent);
5151 if (t->proxy->srvtimeout)
5152 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5153 else
5154 tv_eternity(&t->srexpire);
5155 }
5156 }
5157 return 0;
5158 }
5159 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005160 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005161 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005162 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 +01005163 write(1, trash, len);
5164 }
5165 return 0;
5166 }
5167 return 0;
5168}
5169
5170
willy tarreau5cbea6f2005-12-17 12:48:26 +01005171/* Processes the client and server jobs of a session task, then
5172 * puts it back to the wait queue in a clean state, or
5173 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005174 * the time the task accepts to wait, or TIME_ETERNITY for
5175 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005176 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005177int process_session(struct task *t) {
5178 struct session *s = t->context;
5179 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005180
willy tarreau5cbea6f2005-12-17 12:48:26 +01005181 do {
5182 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005183 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005184 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005185 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005186 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005187 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005188 } while (fsm_resync);
5189
5190 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005191 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005192 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005193
willy tarreau5cbea6f2005-12-17 12:48:26 +01005194 tv_min(&min1, &s->crexpire, &s->cwexpire);
5195 tv_min(&min2, &s->srexpire, &s->swexpire);
5196 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005197 tv_min(&t->expire, &min1, &min2);
5198
5199 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005200 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005201
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005202#ifdef DEBUG_FULL
5203 /* DEBUG code : this should never ever happen, otherwise it indicates
5204 * that a task still has something to do and will provoke a quick loop.
5205 */
5206 if (tv_remain2(&now, &t->expire) <= 0)
5207 exit(100);
5208#endif
5209
willy tarreaub952e1d2005-12-18 01:31:20 +01005210 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005211 }
5212
willy tarreau5cbea6f2005-12-17 12:48:26 +01005213 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005214 actconn--;
5215
willy tarreau982249e2005-12-18 00:57:06 +01005216 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005217 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005218 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 +01005219 write(1, trash, len);
5220 }
5221
willy tarreau750a4722005-12-17 13:21:24 +01005222 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005223 if (s->rep != NULL)
5224 s->logs.bytes = s->rep->total;
5225
willy tarreau9fe663a2005-12-17 13:02:59 +01005226 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005227 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005228 sess_log(s);
5229
willy tarreau0f7af912005-12-17 12:21:26 +01005230 /* the task MUST not be in the run queue anymore */
5231 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005232 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005233 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005234 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005235}
5236
5237
5238
5239/*
5240 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005241 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005242 */
5243int process_chk(struct task *t) {
5244 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005245 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005246 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005247
willy tarreauef900ab2005-12-17 12:52:52 +01005248 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005249
willy tarreau25424f82006-03-19 19:37:48 +01005250 new_chk:
5251 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005252 if (fd < 0) { /* no check currently running */
5253 //fprintf(stderr, "process_chk: 2\n");
5254 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5255 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005256 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005257 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005258
5259 /* we don't send any health-checks when the proxy is stopped or when
5260 * the server should not be checked.
5261 */
5262 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005263 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5264 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005265 task_queue(t); /* restore t to its place in the task list */
5266 return tv_remain2(&now, &t->expire);
5267 }
5268
willy tarreau5cbea6f2005-12-17 12:48:26 +01005269 /* we'll initiate a new check */
5270 s->result = 0; /* no result yet */
5271 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005272 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005273 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5274 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5275 //fprintf(stderr, "process_chk: 3\n");
5276
willy tarreaua41a8b42005-12-17 14:02:24 +01005277 /* we'll connect to the check port on the server */
5278 sa = s->addr;
5279 sa.sin_port = htons(s->check_port);
5280
willy tarreau0174f312005-12-18 01:02:42 +01005281 /* allow specific binding :
5282 * - server-specific at first
5283 * - proxy-specific next
5284 */
5285 if (s->state & SRV_BIND_SRC) {
5286 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5287 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5288 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5289 s->proxy->id, s->id);
5290 s->result = -1;
5291 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005292 }
willy tarreau0174f312005-12-18 01:02:42 +01005293 else if (s->proxy->options & PR_O_BIND_SRC) {
5294 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5295 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5296 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5297 s->proxy->id);
5298 s->result = -1;
5299 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005300 }
willy tarreau0174f312005-12-18 01:02:42 +01005301
5302 if (!s->result) {
5303 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5304 /* OK, connection in progress or established */
5305
5306 //fprintf(stderr, "process_chk: 4\n");
5307
5308 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5309 fdtab[fd].owner = t;
5310 fdtab[fd].read = &event_srv_chk_r;
5311 fdtab[fd].write = &event_srv_chk_w;
5312 fdtab[fd].state = FD_STCONN; /* connection in progress */
5313 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005314#ifdef DEBUG_FULL
5315 assert (!FD_ISSET(fd, StaticReadEvent));
5316#endif
willy tarreau0174f312005-12-18 01:02:42 +01005317 fd_insert(fd);
5318 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5319 tv_delayfrom(&t->expire, &now, s->inter);
5320 task_queue(t); /* restore t to its place in the task list */
5321 return tv_remain(&now, &t->expire);
5322 }
5323 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5324 s->result = -1; /* a real error */
5325 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005326 }
5327 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005328 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005329 }
5330
5331 if (!s->result) { /* nothing done */
5332 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005333 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5334 tv_delayfrom(&t->expire, &t->expire, s->inter);
5335 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005336 }
5337
5338 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005339 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005340 s->health--; /* still good */
5341 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005342 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005343 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005344 recount_servers(s->proxy);
5345 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5346 s->state & SRV_BACKUP ? "Backup " : "",
5347 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5348 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5349 send_log(s->proxy, LOG_ALERT,
5350 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5351 s->state & SRV_BACKUP ? "Backup " : "",
5352 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5353 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreauef900ab2005-12-17 12:52:52 +01005354
willy tarreau62084d42006-03-24 18:57:41 +01005355 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
willy tarreaudd07e972005-12-18 00:48:48 +01005356 Alert("Proxy %s has no server available !\n", s->proxy->id);
5357 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5358 }
5359 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005360 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005361 }
5362
5363 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005364 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005365 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5366 tv_delayfrom(&t->expire, &t->expire, s->inter);
5367 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005368 }
5369 else {
5370 //fprintf(stderr, "process_chk: 8\n");
5371 /* there was a test running */
5372 if (s->result > 0) { /* good server detected */
5373 //fprintf(stderr, "process_chk: 9\n");
5374 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005375 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02005376 s->state |= SRV_RUNNING;
5377
willy tarreau535ae7a2005-12-17 12:58:00 +01005378 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005379 recount_servers(s->proxy);
5380 Warning("%sServer %s/%s UP. %d active and %d backup servers online.%s\n",
5381 s->state & SRV_BACKUP ? "Backup " : "",
5382 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5383 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5384 send_log(s->proxy, LOG_NOTICE,
5385 "%sServer %s/%s is UP. %d active and %d backup servers online.%s\n",
5386 s->state & SRV_BACKUP ? "Backup " : "",
5387 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5388 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreau535ae7a2005-12-17 12:58:00 +01005389 }
willy tarreauef900ab2005-12-17 12:52:52 +01005390
willy tarreaue47c8d72005-12-17 12:55:52 +01005391 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005392 }
willy tarreauef900ab2005-12-17 12:52:52 +01005393 s->curfd = -1; /* no check running anymore */
5394 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005395 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005396 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5397 tv_delayfrom(&t->expire, &t->expire, s->inter);
5398 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005399 }
5400 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5401 //fprintf(stderr, "process_chk: 10\n");
5402 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005403 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005404 s->health--; /* still good */
5405 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005406 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005407
willy tarreau62084d42006-03-24 18:57:41 +01005408 if (s->health == s->rise) {
5409 recount_servers(s->proxy);
5410 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5411 s->state & SRV_BACKUP ? "Backup " : "",
5412 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5413 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5414 send_log(s->proxy, LOG_ALERT,
5415 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5416 s->state & SRV_BACKUP ? "Backup " : "",
5417 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5418 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5419
5420 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5421 Alert("Proxy %s has no server available !\n", s->proxy->id);
5422 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5423 }
5424 }
willy tarreauef900ab2005-12-17 12:52:52 +01005425
willy tarreau5cbea6f2005-12-17 12:48:26 +01005426 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005427 }
5428 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005429 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005430 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005431 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5432 tv_delayfrom(&t->expire, &t->expire, s->inter);
5433 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005434 }
5435 /* if result is 0 and there's no timeout, we have to wait again */
5436 }
5437 //fprintf(stderr, "process_chk: 11\n");
5438 s->result = 0;
5439 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005440 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005441}
5442
5443
willy tarreau5cbea6f2005-12-17 12:48:26 +01005444
willy tarreau0f7af912005-12-17 12:21:26 +01005445#if STATTIME > 0
5446int stats(void);
5447#endif
5448
5449/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005450 * This does 4 things :
5451 * - wake up all expired tasks
5452 * - call all runnable tasks
5453 * - call maintain_proxies() to enable/disable the listeners
5454 * - return the delay till next event in ms, -1 = wait indefinitely
5455 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5456 *
willy tarreau0f7af912005-12-17 12:21:26 +01005457 */
5458
willy tarreau1c2ad212005-12-18 01:11:29 +01005459int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005460 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005461 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005462 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005463
willy tarreaub952e1d2005-12-18 01:31:20 +01005464 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005465
willy tarreau1c2ad212005-12-18 01:11:29 +01005466 /* look for expired tasks and add them to the run queue.
5467 */
5468 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5469 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5470 tnext = t->next;
5471 if (t->state & TASK_RUNNING)
5472 continue;
5473
willy tarreaub952e1d2005-12-18 01:31:20 +01005474 if (tv_iseternity(&t->expire))
5475 continue;
5476
willy tarreau1c2ad212005-12-18 01:11:29 +01005477 /* wakeup expired entries. It doesn't matter if they are
5478 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005479 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005480 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005481 task_wakeup(&rq, t);
5482 }
5483 else {
5484 /* first non-runnable task. Use its expiration date as an upper bound */
5485 int temp_time = tv_remain(&now, &t->expire);
5486 if (temp_time)
5487 next_time = temp_time;
5488 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005489 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005490 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005491
willy tarreau1c2ad212005-12-18 01:11:29 +01005492 /* process each task in the run queue now. Each task may be deleted
5493 * since we only use tnext.
5494 */
5495 tnext = rq;
5496 while ((t = tnext) != NULL) {
5497 int temp_time;
5498
5499 tnext = t->rqnext;
5500 task_sleep(&rq, t);
5501 temp_time = t->process(t);
5502 next_time = MINTIME(temp_time, next_time);
5503 }
5504
5505 /* maintain all proxies in a consistent state. This should quickly become a task */
5506 time2 = maintain_proxies();
5507 return MINTIME(time2, next_time);
5508}
5509
5510
5511#if defined(ENABLE_EPOLL)
5512
5513/*
5514 * Main epoll() loop.
5515 */
5516
5517/* does 3 actions :
5518 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5519 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5520 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5521 *
5522 * returns 0 if initialization failed, !0 otherwise.
5523 */
5524
5525int epoll_loop(int action) {
5526 int next_time;
5527 int status;
5528 int fd;
5529
5530 int fds, count;
5531 int pr, pw, sr, sw;
5532 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5533 struct epoll_event ev;
5534
5535 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005536 static struct epoll_event *epoll_events = NULL;
5537 static int epoll_fd;
5538
5539 if (action == POLL_LOOP_ACTION_INIT) {
5540 epoll_fd = epoll_create(global.maxsock + 1);
5541 if (epoll_fd < 0)
5542 return 0;
5543 else {
5544 epoll_events = (struct epoll_event*)
5545 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5546 PrevReadEvent = (fd_set *)
5547 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5548 PrevWriteEvent = (fd_set *)
5549 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005550 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005551 return 1;
5552 }
5553 else if (action == POLL_LOOP_ACTION_CLEAN) {
5554 if (PrevWriteEvent) free(PrevWriteEvent);
5555 if (PrevReadEvent) free(PrevReadEvent);
5556 if (epoll_events) free(epoll_events);
5557 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005558 epoll_fd = 0;
5559 return 1;
5560 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005561
willy tarreau1c2ad212005-12-18 01:11:29 +01005562 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005563
willy tarreau1c2ad212005-12-18 01:11:29 +01005564 tv_now(&now);
5565
5566 while (1) {
5567 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005568
5569 /* stop when there's no connection left and we don't allow them anymore */
5570 if (!actconn && listeners == 0)
5571 break;
5572
willy tarreau0f7af912005-12-17 12:21:26 +01005573#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005574 {
5575 int time2;
5576 time2 = stats();
5577 next_time = MINTIME(time2, next_time);
5578 }
willy tarreau0f7af912005-12-17 12:21:26 +01005579#endif
5580
willy tarreau1c2ad212005-12-18 01:11:29 +01005581 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5582
5583 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5584 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5585
5586 if ((ro^rn) | (wo^wn)) {
5587 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5588#define FDSETS_ARE_INT_ALIGNED
5589#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005590
willy tarreauad90a0c2005-12-18 01:09:15 +01005591#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5592#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005593 pr = (ro >> count) & 1;
5594 pw = (wo >> count) & 1;
5595 sr = (rn >> count) & 1;
5596 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005597#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005598 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5599 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5600 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5601 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005602#endif
5603#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005604 pr = FD_ISSET(fd, PrevReadEvent);
5605 pw = FD_ISSET(fd, PrevWriteEvent);
5606 sr = FD_ISSET(fd, StaticReadEvent);
5607 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005608#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005609 if (!((sr^pr) | (sw^pw)))
5610 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005611
willy tarreau1c2ad212005-12-18 01:11:29 +01005612 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5613 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005614
willy tarreaub952e1d2005-12-18 01:31:20 +01005615#ifdef EPOLL_CTL_MOD_WORKAROUND
5616 /* I encountered a rarely reproducible problem with
5617 * EPOLL_CTL_MOD where a modified FD (systematically
5618 * the one in epoll_events[0], fd#7) would sometimes
5619 * be set EPOLL_OUT while asked for a read ! This is
5620 * with the 2.4 epoll patch. The workaround is to
5621 * delete then recreate in case of modification.
5622 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5623 * nor RHEL kernels.
5624 */
5625
5626 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5627 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5628
5629 if ((sr | sw))
5630 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5631#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005632 if ((pr | pw)) {
5633 /* the file-descriptor already exists... */
5634 if ((sr | sw)) {
5635 /* ...and it will still exist */
5636 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5637 // perror("epoll_ctl(MOD)");
5638 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005639 }
5640 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005641 /* ...and it will be removed */
5642 if (fdtab[fd].state != FD_STCLOSE &&
5643 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5644 // perror("epoll_ctl(DEL)");
5645 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005646 }
5647 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005648 } else {
5649 /* the file-descriptor did not exist, let's add it */
5650 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5651 // perror("epoll_ctl(ADD)");
5652 // exit(1);
5653 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005654 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005655#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005656 }
5657 ((int*)PrevReadEvent)[fds] = rn;
5658 ((int*)PrevWriteEvent)[fds] = wn;
5659 }
5660 }
5661
5662 /* now let's wait for events */
5663 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5664 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005665
willy tarreau1c2ad212005-12-18 01:11:29 +01005666 for (count = 0; count < status; count++) {
5667 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01005668
5669 if (FD_ISSET(fd, StaticReadEvent)) {
5670 if (fdtab[fd].state == FD_STCLOSE)
5671 continue;
5672 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5673 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005674 }
willy tarreau05be12b2006-03-19 19:35:00 +01005675
5676 if (FD_ISSET(fd, StaticWriteEvent)) {
5677 if (fdtab[fd].state == FD_STCLOSE)
5678 continue;
5679 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5680 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005681 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005682 }
5683 }
5684 return 1;
5685}
5686#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005687
willy tarreauad90a0c2005-12-18 01:09:15 +01005688
willy tarreau5cbea6f2005-12-17 12:48:26 +01005689
willy tarreau1c2ad212005-12-18 01:11:29 +01005690#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005691
willy tarreau1c2ad212005-12-18 01:11:29 +01005692/*
5693 * Main poll() loop.
5694 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005695
willy tarreau1c2ad212005-12-18 01:11:29 +01005696/* does 3 actions :
5697 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5698 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5699 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5700 *
5701 * returns 0 if initialization failed, !0 otherwise.
5702 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005703
willy tarreau1c2ad212005-12-18 01:11:29 +01005704int poll_loop(int action) {
5705 int next_time;
5706 int status;
5707 int fd, nbfd;
5708
5709 int fds, count;
5710 int sr, sw;
5711 unsigned rn, wn; /* read new, write new */
5712
5713 /* private data */
5714 static struct pollfd *poll_events = NULL;
5715
5716 if (action == POLL_LOOP_ACTION_INIT) {
5717 poll_events = (struct pollfd*)
5718 calloc(1, sizeof(struct pollfd) * global.maxsock);
5719 return 1;
5720 }
5721 else if (action == POLL_LOOP_ACTION_CLEAN) {
5722 if (poll_events)
5723 free(poll_events);
5724 return 1;
5725 }
5726
5727 /* OK, it's POLL_LOOP_ACTION_RUN */
5728
5729 tv_now(&now);
5730
5731 while (1) {
5732 next_time = process_runnable_tasks();
5733
5734 /* stop when there's no connection left and we don't allow them anymore */
5735 if (!actconn && listeners == 0)
5736 break;
5737
5738#if STATTIME > 0
5739 {
5740 int time2;
5741 time2 = stats();
5742 next_time = MINTIME(time2, next_time);
5743 }
5744#endif
5745
5746
5747 nbfd = 0;
5748 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5749
5750 rn = ((int*)StaticReadEvent)[fds];
5751 wn = ((int*)StaticWriteEvent)[fds];
5752
5753 if ((rn|wn)) {
5754 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5755#define FDSETS_ARE_INT_ALIGNED
5756#ifdef FDSETS_ARE_INT_ALIGNED
5757
5758#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5759#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5760 sr = (rn >> count) & 1;
5761 sw = (wn >> count) & 1;
5762#else
5763 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5764 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5765#endif
5766#else
5767 sr = FD_ISSET(fd, StaticReadEvent);
5768 sw = FD_ISSET(fd, StaticWriteEvent);
5769#endif
5770 if ((sr|sw)) {
5771 poll_events[nbfd].fd = fd;
5772 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5773 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005774 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005775 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005776 }
5777 }
5778
5779 /* now let's wait for events */
5780 status = poll(poll_events, nbfd, next_time);
5781 tv_now(&now);
5782
5783 for (count = 0; status > 0 && count < nbfd; count++) {
5784 fd = poll_events[count].fd;
5785
5786 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5787 continue;
5788
5789 /* ok, we found one active fd */
5790 status--;
5791
willy tarreau05be12b2006-03-19 19:35:00 +01005792 if (FD_ISSET(fd, StaticReadEvent)) {
5793 if (fdtab[fd].state == FD_STCLOSE)
5794 continue;
5795 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5796 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005797 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005798
willy tarreau05be12b2006-03-19 19:35:00 +01005799 if (FD_ISSET(fd, StaticWriteEvent)) {
5800 if (fdtab[fd].state == FD_STCLOSE)
5801 continue;
5802 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5803 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005804 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005805 }
5806 }
5807 return 1;
5808}
willy tarreauad90a0c2005-12-18 01:09:15 +01005809#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005810
willy tarreauad90a0c2005-12-18 01:09:15 +01005811
willy tarreauad90a0c2005-12-18 01:09:15 +01005812
willy tarreau1c2ad212005-12-18 01:11:29 +01005813/*
5814 * Main select() loop.
5815 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005816
willy tarreau1c2ad212005-12-18 01:11:29 +01005817/* does 3 actions :
5818 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5819 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5820 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5821 *
5822 * returns 0 if initialization failed, !0 otherwise.
5823 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005824
willy tarreauad90a0c2005-12-18 01:09:15 +01005825
willy tarreau1c2ad212005-12-18 01:11:29 +01005826int select_loop(int action) {
5827 int next_time;
5828 int status;
5829 int fd,i;
5830 struct timeval delta;
5831 int readnotnull, writenotnull;
5832 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005833
willy tarreau1c2ad212005-12-18 01:11:29 +01005834 if (action == POLL_LOOP_ACTION_INIT) {
5835 ReadEvent = (fd_set *)
5836 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5837 WriteEvent = (fd_set *)
5838 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5839 return 1;
5840 }
5841 else if (action == POLL_LOOP_ACTION_CLEAN) {
5842 if (WriteEvent) free(WriteEvent);
5843 if (ReadEvent) free(ReadEvent);
5844 return 1;
5845 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005846
willy tarreau1c2ad212005-12-18 01:11:29 +01005847 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005848
willy tarreau1c2ad212005-12-18 01:11:29 +01005849 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005850
willy tarreau1c2ad212005-12-18 01:11:29 +01005851 while (1) {
5852 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005853
willy tarreau1c2ad212005-12-18 01:11:29 +01005854 /* stop when there's no connection left and we don't allow them anymore */
5855 if (!actconn && listeners == 0)
5856 break;
5857
5858#if STATTIME > 0
5859 {
5860 int time2;
5861 time2 = stats();
5862 next_time = MINTIME(time2, next_time);
5863 }
5864#endif
5865
willy tarreau1c2ad212005-12-18 01:11:29 +01005866 if (next_time > 0) { /* FIXME */
5867 /* Convert to timeval */
5868 /* to avoid eventual select loops due to timer precision */
5869 next_time += SCHEDULER_RESOLUTION;
5870 delta.tv_sec = next_time / 1000;
5871 delta.tv_usec = (next_time % 1000) * 1000;
5872 }
5873 else if (next_time == 0) { /* allow select to return immediately when needed */
5874 delta.tv_sec = delta.tv_usec = 0;
5875 }
5876
5877
5878 /* let's restore fdset state */
5879
5880 readnotnull = 0; writenotnull = 0;
5881 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5882 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5883 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5884 }
5885
5886 // /* just a verification code, needs to be removed for performance */
5887 // for (i=0; i<maxfd; i++) {
5888 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5889 // abort();
5890 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5891 // abort();
5892 //
5893 // }
5894
5895 status = select(maxfd,
5896 readnotnull ? ReadEvent : NULL,
5897 writenotnull ? WriteEvent : NULL,
5898 NULL,
5899 (next_time >= 0) ? &delta : NULL);
5900
5901 /* this is an experiment on the separation of the select work */
5902 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5903 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5904
5905 tv_now(&now);
5906
5907 if (status > 0) { /* must proceed with events */
5908
5909 int fds;
5910 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005911
willy tarreau1c2ad212005-12-18 01:11:29 +01005912 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5913 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5914 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5915
5916 /* if we specify read first, the accepts and zero reads will be
5917 * seen first. Moreover, system buffers will be flushed faster.
5918 */
willy tarreau05be12b2006-03-19 19:35:00 +01005919 if (FD_ISSET(fd, ReadEvent)) {
5920 if (fdtab[fd].state == FD_STCLOSE)
5921 continue;
5922 fdtab[fd].read(fd);
5923 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005924
willy tarreau05be12b2006-03-19 19:35:00 +01005925 if (FD_ISSET(fd, WriteEvent)) {
5926 if (fdtab[fd].state == FD_STCLOSE)
5927 continue;
5928 fdtab[fd].write(fd);
5929 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005930 }
5931 }
5932 else {
5933 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005934 }
willy tarreau0f7af912005-12-17 12:21:26 +01005935 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005936 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005937}
5938
5939
5940#if STATTIME > 0
5941/*
5942 * Display proxy statistics regularly. It is designed to be called from the
5943 * select_loop().
5944 */
5945int stats(void) {
5946 static int lines;
5947 static struct timeval nextevt;
5948 static struct timeval lastevt;
5949 static struct timeval starttime = {0,0};
5950 unsigned long totaltime, deltatime;
5951 int ret;
5952
willy tarreau750a4722005-12-17 13:21:24 +01005953 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005954 deltatime = (tv_diff(&lastevt, &now)?:1);
5955 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005956
willy tarreau9fe663a2005-12-17 13:02:59 +01005957 if (global.mode & MODE_STATS) {
5958 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005959 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005960 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5961 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005962 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005963 actconn, totalconn,
5964 stats_tsk_new, stats_tsk_good,
5965 stats_tsk_left, stats_tsk_right,
5966 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5967 }
5968 }
5969
5970 tv_delayfrom(&nextevt, &now, STATTIME);
5971
5972 lastevt=now;
5973 }
5974 ret = tv_remain(&now, &nextevt);
5975 return ret;
5976}
5977#endif
5978
5979
5980/*
5981 * this function enables proxies when there are enough free sessions,
5982 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005983 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005984 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005985 */
5986static int maintain_proxies(void) {
5987 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005988 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005989 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005990
5991 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005992 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005993
5994 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005995 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005996 while (p) {
5997 if (p->nbconn < p->maxconn) {
5998 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005999 for (l = p->listen; l != NULL; l = l->next) {
6000 FD_SET(l->fd, StaticReadEvent);
6001 }
willy tarreau0f7af912005-12-17 12:21:26 +01006002 p->state = PR_STRUN;
6003 }
6004 }
6005 else {
6006 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006007 for (l = p->listen; l != NULL; l = l->next) {
6008 FD_CLR(l->fd, StaticReadEvent);
6009 }
willy tarreau0f7af912005-12-17 12:21:26 +01006010 p->state = PR_STIDLE;
6011 }
6012 }
6013 p = p->next;
6014 }
6015 }
6016 else { /* block all proxies */
6017 while (p) {
6018 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006019 for (l = p->listen; l != NULL; l = l->next) {
6020 FD_CLR(l->fd, StaticReadEvent);
6021 }
willy tarreau0f7af912005-12-17 12:21:26 +01006022 p->state = PR_STIDLE;
6023 }
6024 p = p->next;
6025 }
6026 }
6027
willy tarreau5cbea6f2005-12-17 12:48:26 +01006028 if (stopping) {
6029 p = proxy;
6030 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01006031 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006032 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006033 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006034 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006035 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006036 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006037
willy tarreaua41a8b42005-12-17 14:02:24 +01006038 for (l = p->listen; l != NULL; l = l->next) {
6039 fd_delete(l->fd);
6040 listeners--;
6041 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006042 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006043 }
6044 else {
6045 tleft = MINTIME(t, tleft);
6046 }
6047 }
6048 p = p->next;
6049 }
6050 }
6051 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006052}
6053
6054/*
6055 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006056 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6057 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006058 */
6059static void soft_stop(void) {
6060 struct proxy *p;
6061
6062 stopping = 1;
6063 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006064 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006065 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006066 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006067 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006068 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006069 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006070 }
willy tarreau0f7af912005-12-17 12:21:26 +01006071 p = p->next;
6072 }
6073}
6074
willy tarreaudbd3bef2006-01-20 19:35:18 +01006075static void pause_proxy(struct proxy *p) {
6076 struct listener *l;
6077 for (l = p->listen; l != NULL; l = l->next) {
6078 shutdown(l->fd, SHUT_RD);
6079 FD_CLR(l->fd, StaticReadEvent);
6080 p->state = PR_STPAUSED;
6081 }
6082}
6083
6084/*
6085 * This function temporarily disables listening so that another new instance
6086 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006087 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006088 * the proxy, or a SIGTTIN can be sent to listen again.
6089 */
6090static void pause_proxies(void) {
6091 struct proxy *p;
6092
6093 p = proxy;
6094 tv_now(&now); /* else, the old time before select will be used */
6095 while (p) {
6096 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6097 Warning("Pausing proxy %s.\n", p->id);
6098 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6099 pause_proxy(p);
6100 }
6101 p = p->next;
6102 }
6103}
6104
6105
6106/*
6107 * This function reactivates listening. This can be used after a call to
6108 * sig_pause(), for example when a new instance has failed starting up.
6109 * It is designed to be called upon reception of a SIGTTIN.
6110 */
6111static void listen_proxies(void) {
6112 struct proxy *p;
6113 struct listener *l;
6114
6115 p = proxy;
6116 tv_now(&now); /* else, the old time before select will be used */
6117 while (p) {
6118 if (p->state == PR_STPAUSED) {
6119 Warning("Enabling proxy %s.\n", p->id);
6120 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6121
6122 for (l = p->listen; l != NULL; l = l->next) {
6123 if (listen(l->fd, p->maxconn) == 0) {
6124 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6125 FD_SET(l->fd, StaticReadEvent);
6126 p->state = PR_STRUN;
6127 }
6128 else
6129 p->state = PR_STIDLE;
6130 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006131 int port;
6132
6133 if (l->addr.ss_family == AF_INET6)
6134 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6135 else
6136 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6137
willy tarreaudbd3bef2006-01-20 19:35:18 +01006138 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006139 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006140 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006141 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006142 /* Another port might have been enabled. Let's stop everything. */
6143 pause_proxy(p);
6144 break;
6145 }
6146 }
6147 }
6148 p = p->next;
6149 }
6150}
6151
6152
willy tarreau0f7af912005-12-17 12:21:26 +01006153/*
6154 * upon SIGUSR1, let's have a soft stop.
6155 */
6156void sig_soft_stop(int sig) {
6157 soft_stop();
6158 signal(sig, SIG_IGN);
6159}
6160
willy tarreaudbd3bef2006-01-20 19:35:18 +01006161/*
6162 * upon SIGTTOU, we pause everything
6163 */
6164void sig_pause(int sig) {
6165 pause_proxies();
6166 signal(sig, sig_pause);
6167}
willy tarreau0f7af912005-12-17 12:21:26 +01006168
willy tarreau8337c6b2005-12-17 13:41:01 +01006169/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006170 * upon SIGTTIN, let's have a soft stop.
6171 */
6172void sig_listen(int sig) {
6173 listen_proxies();
6174 signal(sig, sig_listen);
6175}
6176
6177/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006178 * this function dumps every server's state when the process receives SIGHUP.
6179 */
6180void sig_dump_state(int sig) {
6181 struct proxy *p = proxy;
6182
6183 Warning("SIGHUP received, dumping servers states.\n");
6184 while (p) {
6185 struct server *s = p->srv;
6186
6187 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
6188 while (s) {
6189 if (s->state & SRV_RUNNING) {
willy tarreaub1c331f2006-04-07 18:23:29 +02006190 snprintf(trash, sizeof(trash),
6191 "SIGHUP: Server %s/%s is UP. Conn: %d act, %d tot.",
6192 p->id, s->id, s->cur_sess, s->cum_sess);
6193 } else {
6194 snprintf(trash, sizeof(trash),
6195 "SIGHUP: Server %s/%s is DOWN. Conn: %d act, %d tot.",
6196 p->id, s->id, s->cur_sess, s->cum_sess);
willy tarreau8337c6b2005-12-17 13:41:01 +01006197 }
willy tarreaub1c331f2006-04-07 18:23:29 +02006198 Warning("%s\n", trash);
6199 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01006200 s = s->next;
6201 }
willy tarreaudd07e972005-12-18 00:48:48 +01006202
willy tarreau62084d42006-03-24 18:57:41 +01006203 if (p->srv_act == 0) {
6204 if (p->srv_bck) {
willy tarreaub1c331f2006-04-07 18:23:29 +02006205 snprintf(trash, sizeof(trash),
6206 "SIGHUP: Proxy %s is running on backup servers ! Conn: %d act, %d tot.",
6207 p->id, p->nbconn, p->cum_conn);
6208 } else {
6209 snprintf(trash, sizeof(trash),
6210 "SIGHUP: Proxy %s has no server availble ! Conn: %d act, %d tot.",
6211 p->id, p->nbconn, p->cum_conn);
6212 }
6213 } else {
6214 snprintf(trash, sizeof(trash),
6215 "SIGHUP: Proxy %s has %d active servers and %d backup servers availble. Conn: %d act, %d tot.",
6216 p->id, p->srv_act, p->srv_bck, p->nbconn, p->cum_conn);
6217 }
6218 Warning("%s\n", trash);
6219 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01006220
willy tarreau8337c6b2005-12-17 13:41:01 +01006221 p = p->next;
6222 }
6223 signal(sig, sig_dump_state);
6224}
6225
willy tarreau0f7af912005-12-17 12:21:26 +01006226void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006227 struct task *t, *tnext;
6228 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006229
willy tarreau5cbea6f2005-12-17 12:48:26 +01006230 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
6231 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
6232 tnext = t->next;
6233 s = t->context;
6234 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6235 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6236 "req=%d, rep=%d, clifd=%d\n",
6237 s, tv_remain(&now, &t->expire),
6238 s->cli_state,
6239 s->srv_state,
6240 FD_ISSET(s->cli_fd, StaticReadEvent),
6241 FD_ISSET(s->cli_fd, StaticWriteEvent),
6242 FD_ISSET(s->srv_fd, StaticReadEvent),
6243 FD_ISSET(s->srv_fd, StaticWriteEvent),
6244 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6245 );
willy tarreau0f7af912005-12-17 12:21:26 +01006246 }
willy tarreau12350152005-12-18 01:03:27 +01006247}
6248
willy tarreau64a3cc32005-12-18 01:13:11 +01006249#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006250static void fast_stop(void)
6251{
6252 struct proxy *p;
6253 p = proxy;
6254 while (p) {
6255 p->grace = 0;
6256 p = p->next;
6257 }
6258 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006259}
6260
willy tarreau12350152005-12-18 01:03:27 +01006261void sig_int(int sig) {
6262 /* This would normally be a hard stop,
6263 but we want to be sure about deallocation,
6264 and so on, so we do a soft stop with
6265 0 GRACE time
6266 */
6267 fast_stop();
6268 /* If we are killed twice, we decide to die*/
6269 signal(sig, SIG_DFL);
6270}
6271
6272void sig_term(int sig) {
6273 /* This would normally be a hard stop,
6274 but we want to be sure about deallocation,
6275 and so on, so we do a soft stop with
6276 0 GRACE time
6277 */
6278 fast_stop();
6279 /* If we are killed twice, we decide to die*/
6280 signal(sig, SIG_DFL);
6281}
willy tarreau64a3cc32005-12-18 01:13:11 +01006282#endif
willy tarreau12350152005-12-18 01:03:27 +01006283
willy tarreauc1f47532005-12-18 01:08:26 +01006284/* returns the pointer to an error in the replacement string, or NULL if OK */
6285char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006286 struct hdr_exp *exp;
6287
willy tarreauc1f47532005-12-18 01:08:26 +01006288 if (replace != NULL) {
6289 char *err;
6290 err = check_replace_string(replace);
6291 if (err)
6292 return err;
6293 }
6294
willy tarreaue39cd132005-12-17 13:00:18 +01006295 while (*head != NULL)
6296 head = &(*head)->next;
6297
6298 exp = calloc(1, sizeof(struct hdr_exp));
6299
6300 exp->preg = preg;
6301 exp->replace = replace;
6302 exp->action = action;
6303 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006304
6305 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006306}
6307
willy tarreau9fe663a2005-12-17 13:02:59 +01006308
willy tarreau0f7af912005-12-17 12:21:26 +01006309/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006310 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006311 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006312int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006313
willy tarreau9fe663a2005-12-17 13:02:59 +01006314 if (!strcmp(args[0], "global")) { /* new section */
6315 /* no option, nothing special to do */
6316 return 0;
6317 }
6318 else if (!strcmp(args[0], "daemon")) {
6319 global.mode |= MODE_DAEMON;
6320 }
6321 else if (!strcmp(args[0], "debug")) {
6322 global.mode |= MODE_DEBUG;
6323 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006324 else if (!strcmp(args[0], "noepoll")) {
6325 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6326 }
6327 else if (!strcmp(args[0], "nopoll")) {
6328 cfg_polling_mechanism &= ~POLL_USE_POLL;
6329 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006330 else if (!strcmp(args[0], "quiet")) {
6331 global.mode |= MODE_QUIET;
6332 }
6333 else if (!strcmp(args[0], "stats")) {
6334 global.mode |= MODE_STATS;
6335 }
6336 else if (!strcmp(args[0], "uid")) {
6337 if (global.uid != 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 tarreau5cbea6f2005-12-17 12:48:26 +01006344 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006345 global.uid = atol(args[1]);
6346 }
6347 else if (!strcmp(args[0], "gid")) {
6348 if (global.gid != 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 tarreau0f7af912005-12-17 12:21:26 +01006354 return -1;
6355 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006356 global.gid = atol(args[1]);
6357 }
6358 else if (!strcmp(args[0], "nbproc")) {
6359 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006360 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006361 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006362 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006363 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006364 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006365 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006366 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006367 global.nbproc = atol(args[1]);
6368 }
6369 else if (!strcmp(args[0], "maxconn")) {
6370 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006371 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006372 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006373 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006374 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006375 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006376 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006377 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006378 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006379#ifdef SYSTEM_MAXCONN
6380 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6381 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);
6382 global.maxconn = DEFAULT_MAXCONN;
6383 }
6384#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006385 }
willy tarreaub1285d52005-12-18 01:20:14 +01006386 else if (!strcmp(args[0], "ulimit-n")) {
6387 if (global.rlimit_nofile != 0) {
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 an integer argument.\n", file, linenum, args[0]);
6393 return -1;
6394 }
6395 global.rlimit_nofile = atol(args[1]);
6396 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006397 else if (!strcmp(args[0], "chroot")) {
6398 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006399 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006400 return 0;
6401 }
6402 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006403 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006404 return -1;
6405 }
6406 global.chroot = strdup(args[1]);
6407 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006408 else if (!strcmp(args[0], "pidfile")) {
6409 if (global.pidfile != NULL) {
6410 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6411 return 0;
6412 }
6413 if (*(args[1]) == 0) {
6414 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6415 return -1;
6416 }
6417 global.pidfile = strdup(args[1]);
6418 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006419 else if (!strcmp(args[0], "log")) { /* syslog server address */
6420 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006421 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006422
6423 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006424 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006425 return -1;
6426 }
6427
6428 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6429 if (!strcmp(log_facilities[facility], args[2]))
6430 break;
6431
6432 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006433 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006434 exit(1);
6435 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006436
6437 level = 7; /* max syslog level = debug */
6438 if (*(args[3])) {
6439 while (level >= 0 && strcmp(log_levels[level], args[3]))
6440 level--;
6441 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006442 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006443 exit(1);
6444 }
6445 }
6446
willy tarreau9fe663a2005-12-17 13:02:59 +01006447 sa = str2sa(args[1]);
6448 if (!sa->sin_port)
6449 sa->sin_port = htons(SYSLOG_PORT);
6450
6451 if (global.logfac1 == -1) {
6452 global.logsrv1 = *sa;
6453 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006454 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006455 }
6456 else if (global.logfac2 == -1) {
6457 global.logsrv2 = *sa;
6458 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006459 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006460 }
6461 else {
6462 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6463 return -1;
6464 }
6465
6466 }
6467 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006468 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006469 return -1;
6470 }
6471 return 0;
6472}
6473
6474
willy tarreaua41a8b42005-12-17 14:02:24 +01006475void init_default_instance() {
6476 memset(&defproxy, 0, sizeof(defproxy));
6477 defproxy.mode = PR_MODE_TCP;
6478 defproxy.state = PR_STNEW;
6479 defproxy.maxconn = cfg_maxpconn;
6480 defproxy.conn_retries = CONN_RETRIES;
6481 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6482}
6483
willy tarreau9fe663a2005-12-17 13:02:59 +01006484/*
6485 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6486 */
6487int cfg_parse_listen(char *file, int linenum, char **args) {
6488 static struct proxy *curproxy = NULL;
6489 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006490 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006491 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006492
6493 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006494 if (!*args[1]) {
6495 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6496 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006497 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006498 return -1;
6499 }
6500
6501 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006502 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006503 return -1;
6504 }
6505 curproxy->next = proxy;
6506 proxy = curproxy;
6507 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006508
6509 /* parse the listener address if any */
6510 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006511 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006512 if (!curproxy->listen)
6513 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006514 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01006515 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006516
willy tarreau9fe663a2005-12-17 13:02:59 +01006517 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006518 curproxy->state = defproxy.state;
6519 curproxy->maxconn = defproxy.maxconn;
6520 curproxy->conn_retries = defproxy.conn_retries;
6521 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006522
6523 if (defproxy.check_req)
6524 curproxy->check_req = strdup(defproxy.check_req);
6525 curproxy->check_len = defproxy.check_len;
6526
6527 if (defproxy.cookie_name)
6528 curproxy->cookie_name = strdup(defproxy.cookie_name);
6529 curproxy->cookie_len = defproxy.cookie_len;
6530
6531 if (defproxy.capture_name)
6532 curproxy->capture_name = strdup(defproxy.capture_name);
6533 curproxy->capture_namelen = defproxy.capture_namelen;
6534 curproxy->capture_len = defproxy.capture_len;
6535
6536 if (defproxy.errmsg.msg400)
6537 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6538 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6539
6540 if (defproxy.errmsg.msg403)
6541 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6542 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6543
6544 if (defproxy.errmsg.msg408)
6545 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6546 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6547
6548 if (defproxy.errmsg.msg500)
6549 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6550 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6551
6552 if (defproxy.errmsg.msg502)
6553 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6554 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6555
6556 if (defproxy.errmsg.msg503)
6557 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6558 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6559
6560 if (defproxy.errmsg.msg504)
6561 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6562 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6563
willy tarreaua41a8b42005-12-17 14:02:24 +01006564 curproxy->clitimeout = defproxy.clitimeout;
6565 curproxy->contimeout = defproxy.contimeout;
6566 curproxy->srvtimeout = defproxy.srvtimeout;
6567 curproxy->mode = defproxy.mode;
6568 curproxy->logfac1 = defproxy.logfac1;
6569 curproxy->logsrv1 = defproxy.logsrv1;
6570 curproxy->loglev1 = defproxy.loglev1;
6571 curproxy->logfac2 = defproxy.logfac2;
6572 curproxy->logsrv2 = defproxy.logsrv2;
6573 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006574 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006575 curproxy->grace = defproxy.grace;
6576 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006577 curproxy->mon_net = defproxy.mon_net;
6578 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006579 return 0;
6580 }
6581 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006582 /* some variables may have already been initialized earlier */
6583 if (defproxy.check_req) free(defproxy.check_req);
6584 if (defproxy.cookie_name) free(defproxy.cookie_name);
6585 if (defproxy.capture_name) free(defproxy.capture_name);
6586 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6587 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6588 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6589 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6590 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6591 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6592 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6593
6594 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006595 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006596 return 0;
6597 }
6598 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006599 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006600 return -1;
6601 }
6602
willy tarreaua41a8b42005-12-17 14:02:24 +01006603 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6604 if (curproxy == &defproxy) {
6605 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6606 return -1;
6607 }
6608
6609 if (strchr(args[1], ':') == NULL) {
6610 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6611 file, linenum, args[0]);
6612 return -1;
6613 }
6614 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006615 if (!curproxy->listen)
6616 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006617 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006618 return 0;
6619 }
willy tarreaub1285d52005-12-18 01:20:14 +01006620 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6621 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6622 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6623 file, linenum, args[0]);
6624 return -1;
6625 }
6626 /* flush useless bits */
6627 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6628 return 0;
6629 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006630 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006631 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6632 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6633 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6634 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006635 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006636 return -1;
6637 }
6638 }
6639 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006640 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006641 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006642 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6643 curproxy->state = PR_STNEW;
6644 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006645 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6646 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006647// if (curproxy == &defproxy) {
6648// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6649// return -1;
6650// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006651
willy tarreau9fe663a2005-12-17 13:02:59 +01006652 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006653// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6654// file, linenum);
6655// return 0;
6656 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006657 }
6658
6659 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006660 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6661 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006662 return -1;
6663 }
6664 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006665 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006666
6667 cur_arg = 2;
6668 while (*(args[cur_arg])) {
6669 if (!strcmp(args[cur_arg], "rewrite")) {
6670 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006671 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006672 else if (!strcmp(args[cur_arg], "indirect")) {
6673 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006674 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006675 else if (!strcmp(args[cur_arg], "insert")) {
6676 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006677 }
willy tarreau240afa62005-12-17 13:14:35 +01006678 else if (!strcmp(args[cur_arg], "nocache")) {
6679 curproxy->options |= PR_O_COOK_NOC;
6680 }
willy tarreaucd878942005-12-17 13:27:43 +01006681 else if (!strcmp(args[cur_arg], "postonly")) {
6682 curproxy->options |= PR_O_COOK_POST;
6683 }
willy tarreau0174f312005-12-18 01:02:42 +01006684 else if (!strcmp(args[cur_arg], "prefix")) {
6685 curproxy->options |= PR_O_COOK_PFX;
6686 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006687 else {
willy tarreau0174f312005-12-18 01:02:42 +01006688 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006689 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006690 return -1;
6691 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006692 cur_arg++;
6693 }
willy tarreau0174f312005-12-18 01:02:42 +01006694 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6695 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6696 file, linenum);
6697 return -1;
6698 }
6699
6700 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6701 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006702 file, linenum);
6703 return -1;
6704 }
willy tarreau12350152005-12-18 01:03:27 +01006705 }/* end else if (!strcmp(args[0], "cookie")) */
6706 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6707// if (curproxy == &defproxy) {
6708// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6709// return -1;
6710// }
6711
6712 if (curproxy->appsession_name != NULL) {
6713// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6714// file, linenum);
6715// return 0;
6716 free(curproxy->appsession_name);
6717 }
6718
6719 if (*(args[5]) == 0) {
6720 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6721 file, linenum, args[0]);
6722 return -1;
6723 }
6724 have_appsession = 1;
6725 curproxy->appsession_name = strdup(args[1]);
6726 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6727 curproxy->appsession_len = atoi(args[3]);
6728 curproxy->appsession_timeout = atoi(args[5]);
6729 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6730 if (rc) {
6731 Alert("Error Init Appsession Hashtable.\n");
6732 return -1;
6733 }
6734 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006735 else if (!strcmp(args[0], "capture")) {
6736 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6737 // if (curproxy == &defproxy) {
6738 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6739 // return -1;
6740 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006741
willy tarreau4302f492005-12-18 01:00:37 +01006742 if (curproxy->capture_name != NULL) {
6743 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6744 // file, linenum, args[0]);
6745 // return 0;
6746 free(curproxy->capture_name);
6747 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006748
willy tarreau4302f492005-12-18 01:00:37 +01006749 if (*(args[4]) == 0) {
6750 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6751 file, linenum, args[0]);
6752 return -1;
6753 }
6754 curproxy->capture_name = strdup(args[2]);
6755 curproxy->capture_namelen = strlen(curproxy->capture_name);
6756 curproxy->capture_len = atol(args[4]);
6757 if (curproxy->capture_len >= CAPTURE_LEN) {
6758 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6759 file, linenum, CAPTURE_LEN - 1);
6760 curproxy->capture_len = CAPTURE_LEN - 1;
6761 }
6762 curproxy->to_log |= LW_COOKIE;
6763 }
6764 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6765 struct cap_hdr *hdr;
6766
6767 if (curproxy == &defproxy) {
6768 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6769 return -1;
6770 }
6771
6772 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6773 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6774 file, linenum, args[0], args[1]);
6775 return -1;
6776 }
6777
6778 hdr = calloc(sizeof(struct cap_hdr), 1);
6779 hdr->next = curproxy->req_cap;
6780 hdr->name = strdup(args[3]);
6781 hdr->namelen = strlen(args[3]);
6782 hdr->len = atol(args[5]);
6783 hdr->index = curproxy->nb_req_cap++;
6784 curproxy->req_cap = hdr;
6785 curproxy->to_log |= LW_REQHDR;
6786 }
6787 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6788 struct cap_hdr *hdr;
6789
6790 if (curproxy == &defproxy) {
6791 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6792 return -1;
6793 }
6794
6795 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6796 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6797 file, linenum, args[0], args[1]);
6798 return -1;
6799 }
6800 hdr = calloc(sizeof(struct cap_hdr), 1);
6801 hdr->next = curproxy->rsp_cap;
6802 hdr->name = strdup(args[3]);
6803 hdr->namelen = strlen(args[3]);
6804 hdr->len = atol(args[5]);
6805 hdr->index = curproxy->nb_rsp_cap++;
6806 curproxy->rsp_cap = hdr;
6807 curproxy->to_log |= LW_RSPHDR;
6808 }
6809 else {
6810 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006811 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006812 return -1;
6813 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006814 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006815 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006816 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006817 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006818 return 0;
6819 }
6820 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006821 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6822 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006823 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006824 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006825 curproxy->contimeout = atol(args[1]);
6826 }
6827 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006828 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006829 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6830 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006831 return 0;
6832 }
6833 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006834 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6835 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006836 return -1;
6837 }
6838 curproxy->clitimeout = atol(args[1]);
6839 }
6840 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006841 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006842 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006843 return 0;
6844 }
6845 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006846 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6847 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006848 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006849 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006850 curproxy->srvtimeout = atol(args[1]);
6851 }
6852 else if (!strcmp(args[0], "retries")) { /* connection retries */
6853 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006854 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6855 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006856 return -1;
6857 }
6858 curproxy->conn_retries = atol(args[1]);
6859 }
6860 else if (!strcmp(args[0], "option")) {
6861 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006862 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006863 return -1;
6864 }
6865 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006866 /* enable reconnections to dispatch */
6867 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006868#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006869 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006870 /* enable transparent proxy connections */
6871 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006872#endif
6873 else if (!strcmp(args[1], "keepalive"))
6874 /* enable keep-alive */
6875 curproxy->options |= PR_O_KEEPALIVE;
6876 else if (!strcmp(args[1], "forwardfor"))
6877 /* insert x-forwarded-for field */
6878 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006879 else if (!strcmp(args[1], "logasap"))
6880 /* log as soon as possible, without waiting for the session to complete */
6881 curproxy->options |= PR_O_LOGASAP;
6882 else if (!strcmp(args[1], "httpclose"))
6883 /* force connection: close in both directions in HTTP mode */
6884 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01006885 else if (!strcmp(args[1], "forceclose"))
6886 /* force connection: close in both directions in HTTP mode and enforce end of session */
6887 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006888 else if (!strcmp(args[1], "checkcache"))
6889 /* require examination of cacheability of the 'set-cookie' field */
6890 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006891 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006892 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006893 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006894 else if (!strcmp(args[1], "tcplog"))
6895 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006896 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006897 else if (!strcmp(args[1], "dontlognull")) {
6898 /* don't log empty requests */
6899 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006900 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006901 else if (!strcmp(args[1], "tcpka")) {
6902 /* enable TCP keep-alives on client and server sessions */
6903 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6904 }
6905 else if (!strcmp(args[1], "clitcpka")) {
6906 /* enable TCP keep-alives on client sessions */
6907 curproxy->options |= PR_O_TCP_CLI_KA;
6908 }
6909 else if (!strcmp(args[1], "srvtcpka")) {
6910 /* enable TCP keep-alives on server sessions */
6911 curproxy->options |= PR_O_TCP_SRV_KA;
6912 }
Willy TARREAU3481c462006-03-01 22:37:57 +01006913 else if (!strcmp(args[1], "allbackups")) {
6914 /* Use all backup servers simultaneously */
6915 curproxy->options |= PR_O_USE_ALL_BK;
6916 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006917 else if (!strcmp(args[1], "httpchk")) {
6918 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006919 if (curproxy->check_req != NULL) {
6920 free(curproxy->check_req);
6921 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006922 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006923 if (!*args[2]) { /* no argument */
6924 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6925 curproxy->check_len = strlen(DEF_CHECK_REQ);
6926 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006927 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6928 curproxy->check_req = (char *)malloc(reqlen);
6929 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6930 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006931 } else { /* more arguments : METHOD URI [HTTP_VER] */
6932 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6933 if (*args[4])
6934 reqlen += strlen(args[4]);
6935 else
6936 reqlen += strlen("HTTP/1.0");
6937
6938 curproxy->check_req = (char *)malloc(reqlen);
6939 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6940 "%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 +01006941 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006942 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006943 else if (!strcmp(args[1], "persist")) {
6944 /* persist on using the server specified by the cookie, even when it's down */
6945 curproxy->options |= PR_O_PERSIST;
6946 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006947 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006948 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006949 return -1;
6950 }
6951 return 0;
6952 }
6953 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6954 /* enable reconnections to dispatch */
6955 curproxy->options |= PR_O_REDISP;
6956 }
willy tarreaua1598082005-12-17 13:08:06 +01006957#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006958 else if (!strcmp(args[0], "transparent")) {
6959 /* enable transparent proxy connections */
6960 curproxy->options |= PR_O_TRANSP;
6961 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006962#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006963 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6964 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006965 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006966 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006967 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006968 curproxy->maxconn = atol(args[1]);
6969 }
6970 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6971 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006972 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006973 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006974 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006975 curproxy->grace = atol(args[1]);
6976 }
6977 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006978 if (curproxy == &defproxy) {
6979 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6980 return -1;
6981 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006982 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006983 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006984 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006985 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006986 curproxy->dispatch_addr = *str2sa(args[1]);
6987 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006988 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006989 if (*(args[1])) {
6990 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006991 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006992 }
willy tarreau1a3442d2006-03-24 21:03:20 +01006993 else if (!strcmp(args[1], "source")) {
6994 curproxy->options |= PR_O_BALANCE_SH;
6995 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006996 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01006997 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006998 return -1;
6999 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007000 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007001 else /* if no option is set, use round-robin by default */
7002 curproxy->options |= PR_O_BALANCE_RR;
7003 }
7004 else if (!strcmp(args[0], "server")) { /* server address */
7005 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007006 char *rport;
7007 char *raddr;
7008 short realport;
7009 int do_check;
7010
7011 if (curproxy == &defproxy) {
7012 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7013 return -1;
7014 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007015
willy tarreaua41a8b42005-12-17 14:02:24 +01007016 if (!*args[2]) {
7017 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007018 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007019 return -1;
7020 }
7021 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
7022 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7023 return -1;
7024 }
willy tarreau0174f312005-12-18 01:02:42 +01007025
7026 if (curproxy->srv == NULL)
7027 curproxy->srv = newsrv;
7028 else
7029 curproxy->cursrv->next = newsrv;
7030 curproxy->cursrv = newsrv;
7031
7032 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01007033 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007034
7035 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01007036 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01007037 newsrv->id = strdup(args[1]);
7038
7039 /* several ways to check the port component :
7040 * - IP => port=+0, relative
7041 * - IP: => port=+0, relative
7042 * - IP:N => port=N, absolute
7043 * - IP:+N => port=+N, relative
7044 * - IP:-N => port=-N, relative
7045 */
7046 raddr = strdup(args[2]);
7047 rport = strchr(raddr, ':');
7048 if (rport) {
7049 *rport++ = 0;
7050 realport = atol(rport);
7051 if (!isdigit((int)*rport))
7052 newsrv->state |= SRV_MAPPORTS;
7053 } else {
7054 realport = 0;
7055 newsrv->state |= SRV_MAPPORTS;
7056 }
7057
7058 newsrv->addr = *str2sa(raddr);
7059 newsrv->addr.sin_port = htons(realport);
7060 free(raddr);
7061
willy tarreau9fe663a2005-12-17 13:02:59 +01007062 newsrv->curfd = -1; /* no health-check in progress */
7063 newsrv->inter = DEF_CHKINTR;
7064 newsrv->rise = DEF_RISETIME;
7065 newsrv->fall = DEF_FALLTIME;
7066 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7067 cur_arg = 3;
7068 while (*args[cur_arg]) {
7069 if (!strcmp(args[cur_arg], "cookie")) {
7070 newsrv->cookie = strdup(args[cur_arg + 1]);
7071 newsrv->cklen = strlen(args[cur_arg + 1]);
7072 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007073 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007074 else if (!strcmp(args[cur_arg], "rise")) {
7075 newsrv->rise = atol(args[cur_arg + 1]);
7076 newsrv->health = newsrv->rise;
7077 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007078 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007079 else if (!strcmp(args[cur_arg], "fall")) {
7080 newsrv->fall = atol(args[cur_arg + 1]);
7081 cur_arg += 2;
7082 }
7083 else if (!strcmp(args[cur_arg], "inter")) {
7084 newsrv->inter = atol(args[cur_arg + 1]);
7085 cur_arg += 2;
7086 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007087 else if (!strcmp(args[cur_arg], "port")) {
7088 newsrv->check_port = atol(args[cur_arg + 1]);
7089 cur_arg += 2;
7090 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007091 else if (!strcmp(args[cur_arg], "backup")) {
7092 newsrv->state |= SRV_BACKUP;
7093 cur_arg ++;
7094 }
willy tarreau3b002c72006-04-08 21:52:24 +02007095 else if (!strcmp(args[cur_arg], "weight")) {
7096 int w;
7097 w = atol(args[cur_arg + 1]);
7098 if (w < 1 || w > 256) {
7099 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
7100 file, linenum, newsrv->id, w);
7101 return -1;
7102 }
7103 newsrv->uweight = w - 1;
7104 cur_arg += 2;
7105 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007106 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007107 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007108 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007109 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007110 }
willy tarreau0174f312005-12-18 01:02:42 +01007111 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7112 if (!*args[cur_arg + 1]) {
7113 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7114 file, linenum, "source");
7115 return -1;
7116 }
7117 newsrv->state |= SRV_BIND_SRC;
7118 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7119 cur_arg += 2;
7120 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007121 else {
willy tarreau3b002c72006-04-08 21:52:24 +02007122 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 +01007123 file, linenum, newsrv->id);
7124 return -1;
7125 }
7126 }
7127
7128 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007129 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7130 newsrv->check_port = realport; /* by default */
7131 if (!newsrv->check_port) {
7132 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 +01007133 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007134 return -1;
7135 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007136 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007137 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007138
willy tarreau62084d42006-03-24 18:57:41 +01007139 if (newsrv->state & SRV_BACKUP)
7140 curproxy->srv_bck++;
7141 else
7142 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007143 }
7144 else if (!strcmp(args[0], "log")) { /* syslog server address */
7145 struct sockaddr_in *sa;
7146 int facility;
7147
7148 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7149 curproxy->logfac1 = global.logfac1;
7150 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007151 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007152 curproxy->logfac2 = global.logfac2;
7153 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007154 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007155 }
7156 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007157 int level;
7158
willy tarreau0f7af912005-12-17 12:21:26 +01007159 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7160 if (!strcmp(log_facilities[facility], args[2]))
7161 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007162
willy tarreau0f7af912005-12-17 12:21:26 +01007163 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007164 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007165 exit(1);
7166 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007167
willy tarreau8337c6b2005-12-17 13:41:01 +01007168 level = 7; /* max syslog level = debug */
7169 if (*(args[3])) {
7170 while (level >= 0 && strcmp(log_levels[level], args[3]))
7171 level--;
7172 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007173 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007174 exit(1);
7175 }
7176 }
7177
willy tarreau0f7af912005-12-17 12:21:26 +01007178 sa = str2sa(args[1]);
7179 if (!sa->sin_port)
7180 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007181
willy tarreau0f7af912005-12-17 12:21:26 +01007182 if (curproxy->logfac1 == -1) {
7183 curproxy->logsrv1 = *sa;
7184 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007185 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007186 }
7187 else if (curproxy->logfac2 == -1) {
7188 curproxy->logsrv2 = *sa;
7189 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007190 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007191 }
7192 else {
7193 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007194 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007195 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007196 }
7197 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007198 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007199 file, linenum);
7200 return -1;
7201 }
7202 }
willy tarreaua1598082005-12-17 13:08:06 +01007203 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007204 if (!*args[1]) {
7205 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007206 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007207 return -1;
7208 }
7209
7210 curproxy->source_addr = *str2sa(args[1]);
7211 curproxy->options |= PR_O_BIND_SRC;
7212 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007213 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace 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 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007221 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7222 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007223 return -1;
7224 }
7225
7226 preg = calloc(1, sizeof(regex_t));
7227 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007228 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007229 return -1;
7230 }
7231
willy tarreauc1f47532005-12-18 01:08:26 +01007232 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7233 if (err) {
7234 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7235 file, linenum, *err);
7236 return -1;
7237 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007238 }
7239 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7240 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007241 if (curproxy == &defproxy) {
7242 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7243 return -1;
7244 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007245
7246 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007247 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007248 return -1;
7249 }
7250
7251 preg = calloc(1, sizeof(regex_t));
7252 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007253 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007254 return -1;
7255 }
7256
7257 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7258 }
7259 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7260 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007261 if (curproxy == &defproxy) {
7262 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7263 return -1;
7264 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007265
7266 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007267 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007268 return -1;
7269 }
7270
7271 preg = calloc(1, sizeof(regex_t));
7272 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007273 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007274 return -1;
7275 }
7276
7277 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7278 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007279 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7280 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007281 if (curproxy == &defproxy) {
7282 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7283 return -1;
7284 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007285
7286 if (*(args[1]) == 0) {
7287 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7288 return -1;
7289 }
7290
7291 preg = calloc(1, sizeof(regex_t));
7292 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7293 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7294 return -1;
7295 }
7296
7297 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7298 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007299 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7300 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007301 if (curproxy == &defproxy) {
7302 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7303 return -1;
7304 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007305
7306 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007307 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007308 return -1;
7309 }
7310
7311 preg = calloc(1, sizeof(regex_t));
7312 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007313 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007314 return -1;
7315 }
7316
7317 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7318 }
7319 else if (!strcmp(args[0], "reqirep")) { /* replace 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 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007327 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7328 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007329 return -1;
7330 }
7331
7332 preg = calloc(1, sizeof(regex_t));
7333 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007334 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007335 return -1;
7336 }
7337
willy tarreauc1f47532005-12-18 01:08:26 +01007338 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7339 if (err) {
7340 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7341 file, linenum, *err);
7342 return -1;
7343 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007344 }
7345 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7346 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007347 if (curproxy == &defproxy) {
7348 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7349 return -1;
7350 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007351
7352 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007353 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007354 return -1;
7355 }
7356
7357 preg = calloc(1, sizeof(regex_t));
7358 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007359 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007360 return -1;
7361 }
7362
7363 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7364 }
7365 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7366 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007367 if (curproxy == &defproxy) {
7368 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7369 return -1;
7370 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007371
7372 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007373 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007374 return -1;
7375 }
7376
7377 preg = calloc(1, sizeof(regex_t));
7378 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007379 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007380 return -1;
7381 }
7382
7383 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7384 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007385 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7386 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007387 if (curproxy == &defproxy) {
7388 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7389 return -1;
7390 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007391
7392 if (*(args[1]) == 0) {
7393 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7394 return -1;
7395 }
7396
7397 preg = calloc(1, sizeof(regex_t));
7398 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7399 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7400 return -1;
7401 }
7402
7403 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7404 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007405 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7406 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007407 if (curproxy == &defproxy) {
7408 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7409 return -1;
7410 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007411
7412 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007413 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007414 return -1;
7415 }
7416
7417 preg = calloc(1, sizeof(regex_t));
7418 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007419 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007420 return -1;
7421 }
7422
7423 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7424 }
7425 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007426 if (curproxy == &defproxy) {
7427 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7428 return -1;
7429 }
7430
willy tarreau9fe663a2005-12-17 13:02:59 +01007431 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007432 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007433 return 0;
7434 }
7435
7436 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007437 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007438 return -1;
7439 }
7440
willy tarreau4302f492005-12-18 01:00:37 +01007441 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7442 }
7443 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7444 regex_t *preg;
7445
7446 if (*(args[1]) == 0 || *(args[2]) == 0) {
7447 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7448 file, linenum, args[0]);
7449 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007450 }
willy tarreau4302f492005-12-18 01:00:37 +01007451
7452 preg = calloc(1, sizeof(regex_t));
7453 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7454 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7455 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007456 }
willy tarreau4302f492005-12-18 01:00:37 +01007457
willy tarreauc1f47532005-12-18 01:08:26 +01007458 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7459 if (err) {
7460 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7461 file, linenum, *err);
7462 return -1;
7463 }
willy tarreau4302f492005-12-18 01:00:37 +01007464 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007465 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7466 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007467 if (curproxy == &defproxy) {
7468 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7469 return -1;
7470 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007471
7472 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007473 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007474 return -1;
7475 }
willy tarreaue39cd132005-12-17 13:00:18 +01007476
willy tarreau9fe663a2005-12-17 13:02:59 +01007477 preg = calloc(1, sizeof(regex_t));
7478 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007479 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007480 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007481 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007482
willy tarreauc1f47532005-12-18 01:08:26 +01007483 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7484 if (err) {
7485 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7486 file, linenum, *err);
7487 return -1;
7488 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007489 }
willy tarreau982249e2005-12-18 00:57:06 +01007490 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7491 regex_t *preg;
7492 if (curproxy == &defproxy) {
7493 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7494 return -1;
7495 }
7496
7497 if (*(args[1]) == 0) {
7498 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7499 return -1;
7500 }
7501
7502 preg = calloc(1, sizeof(regex_t));
7503 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7504 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7505 return -1;
7506 }
7507
willy tarreauc1f47532005-12-18 01:08:26 +01007508 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, 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 tarreau982249e2005-12-18 00:57:06 +01007514 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007515 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007516 regex_t *preg;
7517 if (curproxy == &defproxy) {
7518 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7519 return -1;
7520 }
willy tarreaue39cd132005-12-17 13:00:18 +01007521
willy tarreaua41a8b42005-12-17 14:02:24 +01007522 if (*(args[1]) == 0 || *(args[2]) == 0) {
7523 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7524 file, linenum, args[0]);
7525 return -1;
7526 }
willy tarreaue39cd132005-12-17 13:00:18 +01007527
willy tarreaua41a8b42005-12-17 14:02:24 +01007528 preg = calloc(1, sizeof(regex_t));
7529 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7530 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7531 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007532 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007533
willy tarreauc1f47532005-12-18 01:08:26 +01007534 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7535 if (err) {
7536 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7537 file, linenum, *err);
7538 return -1;
7539 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007540 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007541 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7542 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007543 if (curproxy == &defproxy) {
7544 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7545 return -1;
7546 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007547
7548 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007549 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007550 return -1;
7551 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007552
willy tarreau9fe663a2005-12-17 13:02:59 +01007553 preg = calloc(1, sizeof(regex_t));
7554 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007555 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007556 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007557 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007558
willy tarreauc1f47532005-12-18 01:08:26 +01007559 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7560 if (err) {
7561 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7562 file, linenum, *err);
7563 return -1;
7564 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007565 }
willy tarreau982249e2005-12-18 00:57:06 +01007566 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7567 regex_t *preg;
7568 if (curproxy == &defproxy) {
7569 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7570 return -1;
7571 }
7572
7573 if (*(args[1]) == 0) {
7574 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7575 return -1;
7576 }
7577
7578 preg = calloc(1, sizeof(regex_t));
7579 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7580 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7581 return -1;
7582 }
7583
willy tarreauc1f47532005-12-18 01:08:26 +01007584 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7585 if (err) {
7586 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7587 file, linenum, *err);
7588 return -1;
7589 }
willy tarreau982249e2005-12-18 00:57:06 +01007590 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007591 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007592 if (curproxy == &defproxy) {
7593 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7594 return -1;
7595 }
7596
willy tarreau9fe663a2005-12-17 13:02:59 +01007597 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007598 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007599 return 0;
7600 }
7601
7602 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007603 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007604 return -1;
7605 }
7606
7607 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7608 }
willy tarreauc1f47532005-12-18 01:08:26 +01007609 else if (!strcmp(args[0], "errorloc") ||
7610 !strcmp(args[0], "errorloc302") ||
7611 !strcmp(args[0], "errorloc303")) { /* error location */
7612 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007613 char *err;
7614
willy tarreaueedaa9f2005-12-17 14:08:03 +01007615 // if (curproxy == &defproxy) {
7616 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7617 // return -1;
7618 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007619
willy tarreau8337c6b2005-12-17 13:41:01 +01007620 if (*(args[2]) == 0) {
7621 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7622 return -1;
7623 }
7624
7625 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007626 if (!strcmp(args[0], "errorloc303")) {
7627 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7628 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7629 } else {
7630 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7631 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7632 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007633
7634 if (errnum == 400) {
7635 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007636 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007637 free(curproxy->errmsg.msg400);
7638 }
7639 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007640 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007641 }
7642 else if (errnum == 403) {
7643 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007644 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007645 free(curproxy->errmsg.msg403);
7646 }
7647 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007648 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007649 }
7650 else if (errnum == 408) {
7651 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007652 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007653 free(curproxy->errmsg.msg408);
7654 }
7655 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007656 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007657 }
7658 else if (errnum == 500) {
7659 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007660 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007661 free(curproxy->errmsg.msg500);
7662 }
7663 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007664 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007665 }
7666 else if (errnum == 502) {
7667 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007668 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007669 free(curproxy->errmsg.msg502);
7670 }
7671 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007672 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007673 }
7674 else if (errnum == 503) {
7675 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007676 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007677 free(curproxy->errmsg.msg503);
7678 }
7679 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007680 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007681 }
7682 else if (errnum == 504) {
7683 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007684 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007685 free(curproxy->errmsg.msg504);
7686 }
7687 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007688 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007689 }
7690 else {
7691 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7692 free(err);
7693 }
7694 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007695 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007696 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007697 return -1;
7698 }
7699 return 0;
7700}
willy tarreaue39cd132005-12-17 13:00:18 +01007701
willy tarreau5cbea6f2005-12-17 12:48:26 +01007702
willy tarreau9fe663a2005-12-17 13:02:59 +01007703/*
7704 * This function reads and parses the configuration file given in the argument.
7705 * returns 0 if OK, -1 if error.
7706 */
7707int readcfgfile(char *file) {
7708 char thisline[256];
7709 char *line;
7710 FILE *f;
7711 int linenum = 0;
7712 char *end;
7713 char *args[MAX_LINE_ARGS];
7714 int arg;
7715 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007716 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007717 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007718
willy tarreau9fe663a2005-12-17 13:02:59 +01007719 struct proxy *curproxy = NULL;
7720 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007721
willy tarreau9fe663a2005-12-17 13:02:59 +01007722 if ((f=fopen(file,"r")) == NULL)
7723 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007724
willy tarreaueedaa9f2005-12-17 14:08:03 +01007725 init_default_instance();
7726
willy tarreau9fe663a2005-12-17 13:02:59 +01007727 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7728 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007729
willy tarreau9fe663a2005-12-17 13:02:59 +01007730 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007731
willy tarreau9fe663a2005-12-17 13:02:59 +01007732 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007733 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007734 line++;
7735
7736 arg = 0;
7737 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007738
willy tarreau9fe663a2005-12-17 13:02:59 +01007739 while (*line && arg < MAX_LINE_ARGS) {
7740 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7741 * C equivalent value. Other combinations left unchanged (eg: \1).
7742 */
7743 if (*line == '\\') {
7744 int skip = 0;
7745 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7746 *line = line[1];
7747 skip = 1;
7748 }
7749 else if (line[1] == 'r') {
7750 *line = '\r';
7751 skip = 1;
7752 }
7753 else if (line[1] == 'n') {
7754 *line = '\n';
7755 skip = 1;
7756 }
7757 else if (line[1] == 't') {
7758 *line = '\t';
7759 skip = 1;
7760 }
willy tarreauc1f47532005-12-18 01:08:26 +01007761 else if (line[1] == 'x') {
7762 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7763 unsigned char hex1, hex2;
7764 hex1 = toupper(line[2]) - '0';
7765 hex2 = toupper(line[3]) - '0';
7766 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7767 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7768 *line = (hex1<<4) + hex2;
7769 skip = 3;
7770 }
7771 else {
7772 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7773 return -1;
7774 }
7775 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007776 if (skip) {
7777 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7778 end -= skip;
7779 }
7780 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007781 }
willy tarreaua1598082005-12-17 13:08:06 +01007782 else if (*line == '#' || *line == '\n' || *line == '\r') {
7783 /* end of string, end of loop */
7784 *line = 0;
7785 break;
7786 }
willy tarreauc29948c2005-12-17 13:10:27 +01007787 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007788 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007789 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007790 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007791 line++;
7792 args[++arg] = line;
7793 }
7794 else {
7795 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007796 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007797 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007798
willy tarreau9fe663a2005-12-17 13:02:59 +01007799 /* empty line */
7800 if (!**args)
7801 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007802
willy tarreau9fe663a2005-12-17 13:02:59 +01007803 /* zero out remaining args */
7804 while (++arg < MAX_LINE_ARGS) {
7805 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007806 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007807
willy tarreaua41a8b42005-12-17 14:02:24 +01007808 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007809 confsect = CFG_LISTEN;
7810 else if (!strcmp(args[0], "global")) /* global config */
7811 confsect = CFG_GLOBAL;
7812 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007813
willy tarreau9fe663a2005-12-17 13:02:59 +01007814 switch (confsect) {
7815 case CFG_LISTEN:
7816 if (cfg_parse_listen(file, linenum, args) < 0)
7817 return -1;
7818 break;
7819 case CFG_GLOBAL:
7820 if (cfg_parse_global(file, linenum, args) < 0)
7821 return -1;
7822 break;
7823 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007824 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007825 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007826 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007827
7828
willy tarreau0f7af912005-12-17 12:21:26 +01007829 }
7830 fclose(f);
7831
7832 /*
7833 * Now, check for the integrity of all that we have collected.
7834 */
7835
Willy TARREAU3759f982006-03-01 22:44:17 +01007836 /* will be needed further to delay some tasks */
7837 tv_now(&now);
7838
willy tarreau0f7af912005-12-17 12:21:26 +01007839 if ((curproxy = proxy) == NULL) {
7840 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7841 file);
7842 return -1;
7843 }
7844
7845 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007846 curproxy->cursrv = NULL;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007847 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007848 curproxy = curproxy->next;
7849 continue;
7850 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007851
7852 if (curproxy->listen == NULL) {
7853 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);
7854 cfgerr++;
7855 }
7856 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007857 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007858 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007859 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7860 file, curproxy->id);
7861 cfgerr++;
7862 }
7863 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7864 if (curproxy->options & PR_O_TRANSP) {
7865 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7866 file, curproxy->id);
7867 cfgerr++;
7868 }
7869 else if (curproxy->srv == NULL) {
7870 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7871 file, curproxy->id);
7872 cfgerr++;
7873 }
willy tarreaua1598082005-12-17 13:08:06 +01007874 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007875 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7876 file, curproxy->id);
7877 }
7878 }
7879 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007880 if (curproxy->cookie_name != NULL) {
7881 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7882 file, curproxy->id);
7883 }
7884 if ((newsrv = curproxy->srv) != NULL) {
7885 Warning("parsing %s : servers will be ignored for listener %s.\n",
7886 file, curproxy->id);
7887 }
willy tarreaue39cd132005-12-17 13:00:18 +01007888 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007889 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7890 file, curproxy->id);
7891 }
willy tarreaue39cd132005-12-17 13:00:18 +01007892 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007893 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7894 file, curproxy->id);
7895 }
7896 }
7897 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7898 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7899 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7900 file, curproxy->id);
7901 cfgerr++;
7902 }
7903 else {
willy tarreau3b002c72006-04-08 21:52:24 +02007904 struct server *srv;
7905 int pgcd;
7906
7907 if (newsrv) {
7908 /* We will factor the weights to reduce the table,
7909 * using Euclide's largest common divisor algorithm
7910 */
7911 pgcd = newsrv->uweight + 1;
7912 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
7913 int t, w;
7914
7915 w = srv->uweight + 1;
7916 while (w) {
7917 t = pgcd % w;
7918 pgcd = w;
7919 w = t;
7920 }
7921 }
7922 for (srv = newsrv; srv; srv = srv->next)
7923 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
willy tarreau0f7af912005-12-17 12:21:26 +01007924 }
7925 }
7926 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007927
7928 if (curproxy->options & PR_O_LOGASAP)
7929 curproxy->to_log &= ~LW_BYTES;
7930
willy tarreau8337c6b2005-12-17 13:41:01 +01007931 if (curproxy->errmsg.msg400 == NULL) {
7932 curproxy->errmsg.msg400 = (char *)HTTP_400;
7933 curproxy->errmsg.len400 = strlen(HTTP_400);
7934 }
7935 if (curproxy->errmsg.msg403 == NULL) {
7936 curproxy->errmsg.msg403 = (char *)HTTP_403;
7937 curproxy->errmsg.len403 = strlen(HTTP_403);
7938 }
7939 if (curproxy->errmsg.msg408 == NULL) {
7940 curproxy->errmsg.msg408 = (char *)HTTP_408;
7941 curproxy->errmsg.len408 = strlen(HTTP_408);
7942 }
7943 if (curproxy->errmsg.msg500 == NULL) {
7944 curproxy->errmsg.msg500 = (char *)HTTP_500;
7945 curproxy->errmsg.len500 = strlen(HTTP_500);
7946 }
7947 if (curproxy->errmsg.msg502 == NULL) {
7948 curproxy->errmsg.msg502 = (char *)HTTP_502;
7949 curproxy->errmsg.len502 = strlen(HTTP_502);
7950 }
7951 if (curproxy->errmsg.msg503 == NULL) {
7952 curproxy->errmsg.msg503 = (char *)HTTP_503;
7953 curproxy->errmsg.len503 = strlen(HTTP_503);
7954 }
7955 if (curproxy->errmsg.msg504 == NULL) {
7956 curproxy->errmsg.msg504 = (char *)HTTP_504;
7957 curproxy->errmsg.len504 = strlen(HTTP_504);
7958 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007959
7960 /* now we'll start this proxy's health checks if any */
7961 /* 1- count the checkers to run simultaneously */
7962 nbchk = 0;
7963 mininter = 0;
7964 newsrv = curproxy->srv;
7965 while (newsrv != NULL) {
7966 if (newsrv->state & SRV_CHECKED) {
7967 if (!mininter || mininter > newsrv->inter)
7968 mininter = newsrv->inter;
7969 nbchk++;
7970 }
7971 newsrv = newsrv->next;
7972 }
7973
7974 /* 2- start them as far as possible from each others while respecting
7975 * their own intervals. For this, we will start them after their own
7976 * interval added to the min interval divided by the number of servers,
7977 * weighted by the server's position in the list.
7978 */
7979 if (nbchk > 0) {
7980 struct task *t;
7981 int srvpos;
7982
7983 newsrv = curproxy->srv;
7984 srvpos = 0;
7985 while (newsrv != NULL) {
7986 /* should this server be checked ? */
7987 if (newsrv->state & SRV_CHECKED) {
7988 if ((t = pool_alloc(task)) == NULL) {
7989 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7990 return -1;
7991 }
7992
7993 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
7994 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
7995 t->state = TASK_IDLE;
7996 t->process = process_chk;
7997 t->context = newsrv;
7998
7999 /* check this every ms */
8000 tv_delayfrom(&t->expire, &now,
8001 newsrv->inter + mininter * srvpos / nbchk);
8002 task_queue(t);
8003 //task_wakeup(&rq, t);
8004 srvpos++;
8005 }
8006 newsrv = newsrv->next;
8007 }
8008 }
8009
willy tarreau0f7af912005-12-17 12:21:26 +01008010 curproxy = curproxy->next;
8011 }
8012 if (cfgerr > 0) {
8013 Alert("Errors found in configuration file, aborting.\n");
8014 return -1;
8015 }
8016 else
8017 return 0;
8018}
8019
8020
8021/*
8022 * This function initializes all the necessary variables. It only returns
8023 * if everything is OK. If something fails, it exits.
8024 */
8025void init(int argc, char **argv) {
8026 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01008027 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01008028 char *old_argv = *argv;
8029 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008030 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008031
8032 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01008033 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01008034 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01008035 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01008036 exit(1);
8037 }
8038
willy tarreau746e26b2006-03-25 11:14:35 +01008039#ifdef HAPROXY_MEMMAX
8040 global.rlimit_memmax = HAPROXY_MEMMAX;
8041#endif
8042
Willy TARREAUa9e75f62006-03-01 22:27:48 +01008043 /* initialize the libc's localtime structures once for all so that we
8044 * won't be missing memory if we want to send alerts under OOM conditions.
8045 */
8046 tv_now(&now);
8047 localtime(&now.tv_sec);
8048
willy tarreau4302f492005-12-18 01:00:37 +01008049 /* initialize the log header encoding map : '{|}"#' should be encoded with
8050 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
8051 * URL encoding only requires '"', '#' to be encoded as well as non-
8052 * printable characters above.
8053 */
8054 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
8055 memset(url_encode_map, 0, sizeof(url_encode_map));
8056 for (i = 0; i < 32; i++) {
8057 FD_SET(i, hdr_encode_map);
8058 FD_SET(i, url_encode_map);
8059 }
8060 for (i = 127; i < 256; i++) {
8061 FD_SET(i, hdr_encode_map);
8062 FD_SET(i, url_encode_map);
8063 }
8064
8065 tmp = "\"#{|}";
8066 while (*tmp) {
8067 FD_SET(*tmp, hdr_encode_map);
8068 tmp++;
8069 }
8070
8071 tmp = "\"#";
8072 while (*tmp) {
8073 FD_SET(*tmp, url_encode_map);
8074 tmp++;
8075 }
8076
willy tarreau64a3cc32005-12-18 01:13:11 +01008077 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8078#if defined(ENABLE_POLL)
8079 cfg_polling_mechanism |= POLL_USE_POLL;
8080#endif
8081#if defined(ENABLE_EPOLL)
8082 cfg_polling_mechanism |= POLL_USE_EPOLL;
8083#endif
8084
willy tarreau0f7af912005-12-17 12:21:26 +01008085 pid = getpid();
8086 progname = *argv;
8087 while ((tmp = strchr(progname, '/')) != NULL)
8088 progname = tmp + 1;
8089
8090 argc--; argv++;
8091 while (argc > 0) {
8092 char *flag;
8093
8094 if (**argv == '-') {
8095 flag = *argv+1;
8096
8097 /* 1 arg */
8098 if (*flag == 'v') {
8099 display_version();
8100 exit(0);
8101 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008102#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008103 else if (*flag == 'd' && flag[1] == 'e')
8104 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008105#endif
8106#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008107 else if (*flag == 'd' && flag[1] == 'p')
8108 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008109#endif
willy tarreau982249e2005-12-18 00:57:06 +01008110 else if (*flag == 'V')
8111 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008112 else if (*flag == 'd' && flag[1] == 'b')
8113 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008114 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008115 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008116 else if (*flag == 'c')
8117 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008118 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008119 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008120 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008121 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01008122#if STATTIME > 0
8123 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01008124 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01008125 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01008126 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01008127#endif
willy tarreau53e99702006-03-25 18:53:50 +01008128 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8129 /* list of pids to finish ('f') or terminate ('t') */
8130
8131 if (flag[1] == 'f')
8132 oldpids_sig = SIGUSR1; /* finish then exit */
8133 else
8134 oldpids_sig = SIGTERM; /* terminate immediately */
8135 argv++; argc--;
8136
8137 if (argc > 0) {
8138 oldpids = calloc(argc, sizeof(int));
8139 while (argc > 0) {
8140 oldpids[nb_oldpids] = atol(*argv);
8141 if (oldpids[nb_oldpids] <= 0)
8142 usage(old_argv);
8143 argc--; argv++;
8144 nb_oldpids++;
8145 }
8146 }
8147 }
willy tarreau0f7af912005-12-17 12:21:26 +01008148 else { /* >=2 args */
8149 argv++; argc--;
8150 if (argc == 0)
8151 usage(old_argv);
8152
8153 switch (*flag) {
8154 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008155 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008156 case 'N' : cfg_maxpconn = atol(*argv); break;
8157 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008158 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008159 default: usage(old_argv);
8160 }
8161 }
8162 }
8163 else
8164 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008165 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008166 }
8167
willy tarreaud0fb4652005-12-18 01:32:04 +01008168 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008169 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8170 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008171
willy tarreau0f7af912005-12-17 12:21:26 +01008172 if (!cfg_cfgfile)
8173 usage(old_argv);
8174
8175 gethostname(hostname, MAX_HOSTNAME_LEN);
8176
willy tarreau12350152005-12-18 01:03:27 +01008177 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008178 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008179 if (readcfgfile(cfg_cfgfile) < 0) {
8180 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8181 exit(1);
8182 }
willy tarreau12350152005-12-18 01:03:27 +01008183 if (have_appsession)
8184 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008185
willy tarreau982249e2005-12-18 00:57:06 +01008186 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008187 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8188 exit(0);
8189 }
8190
willy tarreau9fe663a2005-12-17 13:02:59 +01008191 if (cfg_maxconn > 0)
8192 global.maxconn = cfg_maxconn;
8193
willy tarreaufe2c5c12005-12-17 14:14:34 +01008194 if (cfg_pidfile) {
8195 if (global.pidfile)
8196 free(global.pidfile);
8197 global.pidfile = strdup(cfg_pidfile);
8198 }
8199
willy tarreau9fe663a2005-12-17 13:02:59 +01008200 if (global.maxconn == 0)
8201 global.maxconn = DEFAULT_MAXCONN;
8202
Willy TARREAU203b0b62006-03-12 18:00:28 +01008203 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008204
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008205 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008206 /* command line debug mode inhibits configuration mode */
8207 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8208 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008209 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8210 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008211
8212 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8213 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8214 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8215 }
8216
8217 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008218 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8219 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008220 global.nbproc = 1;
8221 }
8222
8223 if (global.nbproc < 1)
8224 global.nbproc = 1;
8225
willy tarreau0f7af912005-12-17 12:21:26 +01008226 StaticReadEvent = (fd_set *)calloc(1,
8227 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008228 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008229 StaticWriteEvent = (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
8233 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008234 sizeof(struct fdtab) * (global.maxsock));
8235 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008236 fdtab[i].state = FD_STCLOSE;
8237 }
8238}
8239
8240/*
willy tarreau41310e72006-03-25 18:17:56 +01008241 * this function starts all the proxies. Its return value is composed from
8242 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8243 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008244 */
willy tarreau41310e72006-03-25 18:17:56 +01008245int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008246 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008247 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008248 int err = ERR_NONE;
8249 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008250
8251 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008252 if (curproxy->state != PR_STNEW)
8253 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01008254
willy tarreau41310e72006-03-25 18:17:56 +01008255 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01008256 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008257 if (listener->fd != -1)
8258 continue; /* already initialized */
8259
8260 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
8261 if (verbose)
8262 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8263 curproxy->id);
8264 err |= ERR_RETRYABLE;
8265 pxerr |= 1;
8266 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008267 }
willy tarreau0f7af912005-12-17 12:21:26 +01008268
willy tarreaua41a8b42005-12-17 14:02:24 +01008269 if (fd >= global.maxsock) {
8270 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
8271 curproxy->id);
8272 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008273 err |= ERR_FATAL;
8274 pxerr |= 1;
8275 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008276 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008277
willy tarreaua41a8b42005-12-17 14:02:24 +01008278 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
8279 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
8280 (char *) &one, sizeof(one)) == -1)) {
8281 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
8282 curproxy->id);
8283 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008284 err |= ERR_FATAL;
8285 pxerr |= 1;
8286 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008287 }
willy tarreau0f7af912005-12-17 12:21:26 +01008288
willy tarreaua41a8b42005-12-17 14:02:24 +01008289 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8290 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8291 curproxy->id);
8292 }
willy tarreau0f7af912005-12-17 12:21:26 +01008293
willy tarreaua41a8b42005-12-17 14:02:24 +01008294 if (bind(fd,
8295 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008296 listener->addr.ss_family == AF_INET6 ?
8297 sizeof(struct sockaddr_in6) :
8298 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008299 if (verbose)
8300 Alert("cannot bind socket for proxy %s. Aborting.\n",
8301 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008302 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008303 err |= ERR_RETRYABLE;
8304 pxerr |= 1;
8305 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008306 }
willy tarreau0f7af912005-12-17 12:21:26 +01008307
willy tarreaua41a8b42005-12-17 14:02:24 +01008308 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008309 if (verbose)
8310 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8311 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008312 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008313 err |= ERR_RETRYABLE;
8314 pxerr |= 1;
8315 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008316 }
willy tarreau0f7af912005-12-17 12:21:26 +01008317
willy tarreau41310e72006-03-25 18:17:56 +01008318 /* the socket is ready */
8319 listener->fd = fd;
8320
willy tarreaua41a8b42005-12-17 14:02:24 +01008321 /* the function for the accept() event */
8322 fdtab[fd].read = &event_accept;
8323 fdtab[fd].write = NULL; /* never called */
8324 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01008325 fdtab[fd].state = FD_STLISTEN;
8326 FD_SET(fd, StaticReadEvent);
8327 fd_insert(fd);
8328 listeners++;
8329 }
willy tarreau41310e72006-03-25 18:17:56 +01008330
8331 if (!pxerr) {
8332 curproxy->state = PR_STRUN;
8333 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
8334 }
willy tarreau0f7af912005-12-17 12:21:26 +01008335 }
willy tarreau41310e72006-03-25 18:17:56 +01008336
8337 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01008338}
8339
willy tarreaub952e1d2005-12-18 01:31:20 +01008340int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008341
8342 appsess *temp1,*temp2;
8343 temp1 = (appsess *)key1;
8344 temp2 = (appsess *)key2;
8345
8346 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8347 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8348
8349 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8350}/* end match_str */
8351
willy tarreaub952e1d2005-12-18 01:31:20 +01008352void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008353 appsess *temp1;
8354
8355 //printf("destroy called\n");
8356 temp1 = (appsess *)data;
8357
8358 if (temp1->sessid)
8359 pool_free_to(apools.sessid, temp1->sessid);
8360
8361 if (temp1->serverid)
8362 pool_free_to(apools.serverid, temp1->serverid);
8363
8364 pool_free(appsess, temp1);
8365} /* end destroy */
8366
8367void appsession_cleanup( void )
8368{
8369 struct proxy *p = proxy;
8370
8371 while(p) {
8372 chtbl_destroy(&(p->htbl_proxy));
8373 p = p->next;
8374 }
8375}/* end appsession_cleanup() */
8376
8377void pool_destroy(void **pool)
8378{
8379 void *temp, *next;
8380 next = pool;
8381 while (next) {
8382 temp = next;
8383 next = *(void **)temp;
8384 free(temp);
8385 }
8386}/* end pool_destroy() */
8387
willy tarreaub952e1d2005-12-18 01:31:20 +01008388void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008389 struct proxy *p = proxy;
8390 struct cap_hdr *h,*h_next;
8391 struct server *s,*s_next;
8392 struct listener *l,*l_next;
8393
8394 while (p) {
8395 if (p->id)
8396 free(p->id);
8397
8398 if (p->check_req)
8399 free(p->check_req);
8400
8401 if (p->cookie_name)
8402 free(p->cookie_name);
8403
8404 if (p->capture_name)
8405 free(p->capture_name);
8406
8407 /* only strup if the user have set in config.
8408 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008409 if (p->errmsg.msg400) free(p->errmsg.msg400);
8410 if (p->errmsg.msg403) free(p->errmsg.msg403);
8411 if (p->errmsg.msg408) free(p->errmsg.msg408);
8412 if (p->errmsg.msg500) free(p->errmsg.msg500);
8413 if (p->errmsg.msg502) free(p->errmsg.msg502);
8414 if (p->errmsg.msg503) free(p->errmsg.msg503);
8415 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008416 */
8417 if (p->appsession_name)
8418 free(p->appsession_name);
8419
8420 h = p->req_cap;
8421 while (h) {
8422 h_next = h->next;
8423 if (h->name)
8424 free(h->name);
8425 pool_destroy(h->pool);
8426 free(h);
8427 h = h_next;
8428 }/* end while(h) */
8429
8430 h = p->rsp_cap;
8431 while (h) {
8432 h_next = h->next;
8433 if (h->name)
8434 free(h->name);
8435
8436 pool_destroy(h->pool);
8437 free(h);
8438 h = h_next;
8439 }/* end while(h) */
8440
8441 s = p->srv;
8442 while (s) {
8443 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008444 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008445 free(s->id);
8446
willy tarreaub952e1d2005-12-18 01:31:20 +01008447 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008448 free(s->cookie);
8449
8450 free(s);
8451 s = s_next;
8452 }/* end while(s) */
8453
8454 l = p->listen;
8455 while (l) {
8456 l_next = l->next;
8457 free(l);
8458 l = l_next;
8459 }/* end while(l) */
8460
8461 pool_destroy((void **) p->req_cap_pool);
8462 pool_destroy((void **) p->rsp_cap_pool);
8463 p = p->next;
8464 }/* end while(p) */
8465
8466 if (global.chroot) free(global.chroot);
8467 if (global.pidfile) free(global.pidfile);
8468
willy tarreau12350152005-12-18 01:03:27 +01008469 if (StaticReadEvent) free(StaticReadEvent);
8470 if (StaticWriteEvent) free(StaticWriteEvent);
8471 if (fdtab) free(fdtab);
8472
8473 pool_destroy(pool_session);
8474 pool_destroy(pool_buffer);
8475 pool_destroy(pool_fdtab);
8476 pool_destroy(pool_requri);
8477 pool_destroy(pool_task);
8478 pool_destroy(pool_capture);
8479 pool_destroy(pool_appsess);
8480
8481 if (have_appsession) {
8482 pool_destroy(apools.serverid);
8483 pool_destroy(apools.sessid);
8484 }
8485} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008486
willy tarreau41310e72006-03-25 18:17:56 +01008487/* sends the signal <sig> to all pids found in <oldpids> */
8488static void tell_old_pids(int sig) {
8489 int p;
8490 for (p = 0; p < nb_oldpids; p++)
8491 kill(oldpids[p], sig);
8492}
8493
willy tarreau0f7af912005-12-17 12:21:26 +01008494int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01008495 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01008496 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008497 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008498 init(argc, argv);
8499
willy tarreau0f7af912005-12-17 12:21:26 +01008500 signal(SIGQUIT, dump);
8501 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008502 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008503#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008504 signal(SIGINT, sig_int);
8505 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008506#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008507
8508 /* on very high loads, a sigpipe sometimes happen just between the
8509 * getsockopt() which tells "it's OK to write", and the following write :-(
8510 */
willy tarreau3242e862005-12-17 12:27:53 +01008511#ifndef MSG_NOSIGNAL
8512 signal(SIGPIPE, SIG_IGN);
8513#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008514
willy tarreau41310e72006-03-25 18:17:56 +01008515 /* We will loop at most 100 times with 10 ms delay each time.
8516 * That's at most 1 second. We only send a signal to old pids
8517 * if we cannot grab at least one port.
8518 */
8519 retry = MAX_START_RETRIES;
8520 err = ERR_NONE;
8521 while (retry >= 0) {
8522 struct timeval w;
8523 err = start_proxies(retry == 0 || nb_oldpids == 0);
8524 if (err != ERR_RETRYABLE)
8525 break;
8526 if (nb_oldpids == 0)
8527 break;
8528
8529 tell_old_pids(SIGTTOU);
8530 /* give some time to old processes to stop listening */
8531 w.tv_sec = 0;
8532 w.tv_usec = 10*1000;
8533 select(0, NULL, NULL, NULL, &w);
8534 retry--;
8535 }
8536
8537 /* Note: start_proxies() sends an alert when it fails. */
8538 if (err != ERR_NONE) {
8539 if (retry != MAX_START_RETRIES && nb_oldpids)
8540 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01008541 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01008542 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008543
8544 if (listeners == 0) {
8545 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008546 /* Note: we don't have to send anything to the old pids because we
8547 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01008548 exit(1);
8549 }
8550
willy tarreaudbd3bef2006-01-20 19:35:18 +01008551 /* prepare pause/play signals */
8552 signal(SIGTTOU, sig_pause);
8553 signal(SIGTTIN, sig_listen);
8554
Willy TARREAUe3283d12006-03-01 22:15:29 +01008555 if (global.mode & MODE_DAEMON) {
8556 global.mode &= ~MODE_VERBOSE;
8557 global.mode |= MODE_QUIET;
8558 }
8559
willy tarreaud0fb4652005-12-18 01:32:04 +01008560 /* MODE_QUIET can inhibit alerts and warnings below this line */
8561
8562 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008563 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008564 /* detach from the tty */
8565 fclose(stdin); fclose(stdout); fclose(stderr);
8566 close(0); close(1); close(2);
8567 }
willy tarreau0f7af912005-12-17 12:21:26 +01008568
willy tarreaufe2c5c12005-12-17 14:14:34 +01008569 /* open log & pid files before the chroot */
8570 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8571 int pidfd;
8572 unlink(global.pidfile);
8573 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8574 if (pidfd < 0) {
8575 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01008576 if (nb_oldpids)
8577 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01008578 exit(1);
8579 }
8580 pidfile = fdopen(pidfd, "w");
8581 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008582
8583 /* chroot if needed */
8584 if (global.chroot != NULL) {
8585 if (chroot(global.chroot) == -1) {
8586 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01008587 if (nb_oldpids)
8588 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01008589 }
8590 chdir("/");
8591 }
8592
willy tarreaub1285d52005-12-18 01:20:14 +01008593 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01008594 if (!global.rlimit_nofile)
8595 global.rlimit_nofile = global.maxsock;
8596
willy tarreaub1285d52005-12-18 01:20:14 +01008597 if (global.rlimit_nofile) {
8598 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8599 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8600 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8601 }
willy tarreau746e26b2006-03-25 11:14:35 +01008602 }
8603
8604 if (global.rlimit_memmax) {
8605 limit.rlim_cur = limit.rlim_max =
8606 global.rlimit_memmax * 1048576 / global.nbproc;
8607#ifdef RLIMIT_AS
8608 if (setrlimit(RLIMIT_AS, &limit) == -1) {
8609 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8610 argv[0], global.rlimit_memmax);
8611 }
8612#else
8613 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
8614 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8615 argv[0], global.rlimit_memmax);
8616 }
8617#endif
willy tarreaub1285d52005-12-18 01:20:14 +01008618 }
8619
willy tarreau41310e72006-03-25 18:17:56 +01008620 if (nb_oldpids)
8621 tell_old_pids(oldpids_sig);
8622
8623 /* Note that any error at this stage will be fatal because we will not
8624 * be able to restart the old pids.
8625 */
8626
willy tarreau9fe663a2005-12-17 13:02:59 +01008627 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008628 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008629 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8630 exit(1);
8631 }
8632
willy tarreau036e1ce2005-12-17 13:46:33 +01008633 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008634 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8635 exit(1);
8636 }
8637
willy tarreaub1285d52005-12-18 01:20:14 +01008638 /* check ulimits */
8639 limit.rlim_cur = limit.rlim_max = 0;
8640 getrlimit(RLIMIT_NOFILE, &limit);
8641 if (limit.rlim_cur < global.maxsock) {
8642 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",
8643 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8644 }
8645
willy tarreau9fe663a2005-12-17 13:02:59 +01008646 if (global.mode & MODE_DAEMON) {
8647 int ret = 0;
8648 int proc;
8649
8650 /* the father launches the required number of processes */
8651 for (proc = 0; proc < global.nbproc; proc++) {
8652 ret = fork();
8653 if (ret < 0) {
8654 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008655 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01008656 exit(1); /* there has been an error */
8657 }
8658 else if (ret == 0) /* child breaks here */
8659 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008660 if (pidfile != NULL) {
8661 fprintf(pidfile, "%d\n", ret);
8662 fflush(pidfile);
8663 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008664 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008665 /* close the pidfile both in children and father */
8666 if (pidfile != NULL)
8667 fclose(pidfile);
8668 free(global.pidfile);
8669
willy tarreau9fe663a2005-12-17 13:02:59 +01008670 if (proc == global.nbproc)
8671 exit(0); /* parent must leave */
8672
willy tarreau750a4722005-12-17 13:21:24 +01008673 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8674 * that we can detach from the TTY. We MUST NOT do it in other cases since
8675 * it would have already be done, and 0-2 would have been affected to listening
8676 * sockets
8677 */
8678 if (!(global.mode & MODE_QUIET)) {
8679 /* detach from the tty */
8680 fclose(stdin); fclose(stdout); fclose(stderr);
8681 close(0); close(1); close(2); /* close all fd's */
8682 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8683 }
willy tarreaua1598082005-12-17 13:08:06 +01008684 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008685 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008686 }
8687
willy tarreau1c2ad212005-12-18 01:11:29 +01008688#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008689 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008690 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8691 epoll_loop(POLL_LOOP_ACTION_RUN);
8692 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008693 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008694 }
8695 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008696 Warning("epoll() is not available. Using poll()/select() instead.\n");
8697 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008698 }
8699 }
8700#endif
8701
8702#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008703 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008704 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8705 poll_loop(POLL_LOOP_ACTION_RUN);
8706 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008707 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008708 }
8709 else {
8710 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008711 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008712 }
8713 }
8714#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008715 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008716 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8717 select_loop(POLL_LOOP_ACTION_RUN);
8718 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008719 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008720 }
8721 }
8722
willy tarreau0f7af912005-12-17 12:21:26 +01008723
willy tarreau12350152005-12-18 01:03:27 +01008724 /* Free all Hash Keys and all Hash elements */
8725 appsession_cleanup();
8726 /* Do some cleanup */
8727 deinit();
8728
willy tarreau0f7af912005-12-17 12:21:26 +01008729 exit(0);
8730}
willy tarreau12350152005-12-18 01:03:27 +01008731
8732#if defined(DEBUG_HASH)
8733static void print_table(const CHTbl *htbl) {
8734
8735 ListElmt *element;
8736 int i;
8737 appsess *asession;
8738
8739 /*****************************************************************************
8740 * *
8741 * Display the chained hash table. *
8742 * *
8743 *****************************************************************************/
8744
8745 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8746
8747 for (i = 0; i < TBLSIZ; i++) {
8748 fprintf(stdout, "Bucket[%03d]\n", i);
8749
8750 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8751 //fprintf(stdout, "%c", *(char *)list_data(element));
8752 asession = (appsess *)list_data(element);
8753 fprintf(stdout, "ELEM :%s:", asession->sessid);
8754 fprintf(stdout, " Server :%s: \n", asession->serverid);
8755 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8756 }
8757
8758 fprintf(stdout, "\n");
8759 }
8760 return;
8761} /* end print_table */
8762#endif
8763
8764static int appsession_init(void)
8765{
8766 static int initialized = 0;
8767 int idlen;
8768 struct server *s;
8769 struct proxy *p = proxy;
8770
8771 if (!initialized) {
8772 if (!appsession_task_init()) {
8773 apools.sessid = NULL;
8774 apools.serverid = NULL;
8775 apools.ser_waste = 0;
8776 apools.ser_use = 0;
8777 apools.ser_msize = sizeof(void *);
8778 apools.ses_waste = 0;
8779 apools.ses_use = 0;
8780 apools.ses_msize = sizeof(void *);
8781 while (p) {
8782 s = p->srv;
8783 if (apools.ses_msize < p->appsession_len)
8784 apools.ses_msize = p->appsession_len;
8785 while (s) {
8786 idlen = strlen(s->id);
8787 if (apools.ser_msize < idlen)
8788 apools.ser_msize = idlen;
8789 s = s->next;
8790 }
8791 p = p->next;
8792 }
8793 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8794 apools.ses_msize ++;
8795 }
8796 else {
8797 fprintf(stderr, "appsession_task_init failed\n");
8798 return -1;
8799 }
8800 initialized ++;
8801 }
8802 return 0;
8803}
8804
8805static int appsession_task_init(void)
8806{
8807 static int initialized = 0;
8808 struct task *t;
8809 if (!initialized) {
8810 if ((t = pool_alloc(task)) == NULL)
8811 return -1;
8812 t->next = t->prev = t->rqnext = NULL;
8813 t->wq = LIST_HEAD(wait_queue);
8814 t->state = TASK_IDLE;
8815 t->context = NULL;
8816 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8817 task_queue(t);
8818 t->process = appsession_refresh;
8819 initialized ++;
8820 }
8821 return 0;
8822}
8823
8824static int appsession_refresh(struct task *t) {
8825 struct proxy *p = proxy;
8826 CHTbl *htbl;
8827 ListElmt *element, *last;
8828 int i;
8829 appsess *asession;
8830 void *data;
8831
8832 while (p) {
8833 if (p->appsession_name != NULL) {
8834 htbl = &p->htbl_proxy;
8835 /* if we ever give up the use of TBLSIZ, we need to change this */
8836 for (i = 0; i < TBLSIZ; i++) {
8837 last = NULL;
8838 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8839 asession = (appsess *)list_data(element);
8840 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8841 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8842 int len;
8843 /*
8844 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8845 */
8846 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8847 asession->sessid, asession->serverid?asession->serverid:"(null)");
8848 write(1, trash, len);
8849 }
8850 /* delete the expired element from within the hash table */
8851 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8852 && (htbl->table[i].destroy != NULL)) {
8853 htbl->table[i].destroy(data);
8854 }
8855 if (last == NULL) {/* patient lost his head, get a new one */
8856 element = list_head(&htbl->table[i]);
8857 if (element == NULL) break; /* no heads left, go to next patient */
8858 }
8859 else
8860 element = last;
8861 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8862 else
8863 last = element;
8864 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8865 }
8866 }
8867 p = p->next;
8868 }
8869 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8870 return TBLCHKINT;
8871} /* end appsession_refresh */
8872