blob: e51ae32f32b996600061f32191e76ba4cec2f5b9 [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 tarreau18a957c2006-04-12 19:26:23 +020089#include "include/mini-clist.h"
willy tarreau12350152005-12-18 01:03:27 +010090
willy tarreaubfad5742006-03-23 14:19:11 +010091#ifndef HAPROXY_VERSION
willy tarreauc0d4bbd2006-04-15 21:47:50 +020092#define HAPROXY_VERSION "1.2.12"
willy tarreaubfad5742006-03-23 14:19:11 +010093#endif
94
95#ifndef HAPROXY_DATE
willy tarreauc0d4bbd2006-04-15 21:47:50 +020096#define HAPROXY_DATE "2006/04/15"
willy tarreaubfad5742006-03-23 14:19:11 +010097#endif
willy tarreau0f7af912005-12-17 12:21:26 +010098
99/* this is for libc5 for example */
100#ifndef TCP_NODELAY
101#define TCP_NODELAY 1
102#endif
103
104#ifndef SHUT_RD
105#define SHUT_RD 0
106#endif
107
108#ifndef SHUT_WR
109#define SHUT_WR 1
110#endif
111
willy tarreau0174f312005-12-18 01:02:42 +0100112/*
113 * BUFSIZE defines the size of a read and write buffer. It is the maximum
114 * amount of bytes which can be stored by the proxy for each session. However,
115 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
116 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
117 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
118 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
119 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
120 */
121#ifndef BUFSIZE
122#define BUFSIZE 16384
123#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100124
125// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100126#ifndef MAXREWRITE
127#define MAXREWRITE (BUFSIZE / 2)
128#endif
129
willy tarreau9fe663a2005-12-17 13:02:59 +0100130#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100131#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100132
willy tarreau5cbea6f2005-12-17 12:48:26 +0100133// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100134#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100135
willy tarreaue39cd132005-12-17 13:00:18 +0100136// max # of added headers per request
137#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100138
139// max # of matches per regexp
140#define MAX_MATCH 10
141
willy tarreau0174f312005-12-18 01:02:42 +0100142// cookie delimitor in "prefix" mode. This character is inserted between the
143// persistence cookie and the original value. The '~' is allowed by RFC2965,
144// and should not be too common in server names.
145#ifndef COOKIE_DELIM
146#define COOKIE_DELIM '~'
147#endif
148
willy tarreau0f7af912005-12-17 12:21:26 +0100149#define CONN_RETRIES 3
150
willy tarreau5cbea6f2005-12-17 12:48:26 +0100151#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100152#define DEF_CHKINTR 2000
153#define DEF_FALLTIME 3
154#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100155#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100156
Willy TARREAU13032e72006-03-12 17:31:45 +0100157/* Default connections limit.
158 *
159 * A system limit can be enforced at build time in order to avoid using haproxy
160 * beyond reasonable system limits. For this, just define SYSTEM_MAXCONN to the
161 * absolute limit accepted by the system. If the configuration specifies a
162 * higher value, it will be capped to SYSTEM_MAXCONN and a warning will be
163 * emitted. The only way to override this limit will be to set it via the
164 * command-line '-n' argument.
165 */
166#ifndef SYSTEM_MAXCONN
willy tarreau9fe663a2005-12-17 13:02:59 +0100167#define DEFAULT_MAXCONN 2000
Willy TARREAU13032e72006-03-12 17:31:45 +0100168#else
169#define DEFAULT_MAXCONN SYSTEM_MAXCONN
170#endif
willy tarreau9fe663a2005-12-17 13:02:59 +0100171
willy tarreau0f7af912005-12-17 12:21:26 +0100172/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
173#define INTBITS 5
174
175/* show stats this every millisecond, 0 to disable */
176#ifndef STATTIME
177#define STATTIME 2000
178#endif
179
willy tarreau5cbea6f2005-12-17 12:48:26 +0100180/* this reduces the number of calls to select() by choosing appropriate
181 * sheduler precision in milliseconds. It should be near the minimum
182 * time that is needed by select() to collect all events. All timeouts
183 * are rounded up by adding this value prior to pass it to select().
184 */
185#define SCHEDULER_RESOLUTION 9
186
willy tarreaub952e1d2005-12-18 01:31:20 +0100187#define TIME_ETERNITY -1
188/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100189#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
190#define SETNOW(a) (*a=now)
191
willy tarreau9da061b2005-12-17 12:29:56 +0100192/****** string-specific macros and functions ******/
193/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
194#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
195
196/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
197#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
198
willy tarreau0174f312005-12-18 01:02:42 +0100199/* returns 1 only if only zero or one bit is set in X, which means that X is a
200 * power of 2, and 0 otherwise */
201#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100202/*
203 * copies at most <size-1> chars from <src> to <dst>. Last char is always
204 * set to 0, unless <size> is 0. The number of chars copied is returned
205 * (excluding the terminating zero).
206 * This code has been optimized for size and speed : on x86, it's 45 bytes
207 * long, uses only registers, and consumes only 4 cycles per char.
208 */
willy tarreau750a4722005-12-17 13:21:24 +0100209int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100210 char *orig = dst;
211 if (size) {
212 while (--size && (*dst = *src)) {
213 src++; dst++;
214 }
215 *dst = 0;
216 }
217 return dst - orig;
218}
willy tarreau9da061b2005-12-17 12:29:56 +0100219
willy tarreau4302f492005-12-18 01:00:37 +0100220/*
221 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
222 * dynamically allocated. In the first case, <__pool> is updated to point to
223 * the next element in the list.
224 */
225#define pool_alloc_from(__pool, __len) ({ \
226 void *__p; \
227 if ((__p = (__pool)) == NULL) \
228 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
229 else { \
230 __pool = *(void **)(__pool); \
231 } \
232 __p; \
233})
234
235/*
236 * Puts a memory area back to the corresponding pool.
237 * Items are chained directly through a pointer that
238 * is written in the beginning of the memory area, so
239 * there's no need for any carrier cell. This implies
240 * that each memory area is at least as big as one
241 * pointer.
242 */
243#define pool_free_to(__pool, __ptr) ({ \
244 *(void **)(__ptr) = (void *)(__pool); \
245 __pool = (void *)(__ptr); \
246})
247
248
willy tarreau0f7af912005-12-17 12:21:26 +0100249#define MEM_OPTIM
250#ifdef MEM_OPTIM
251/*
252 * Returns a pointer to type <type> taken from the
253 * pool <pool_type> or dynamically allocated. In the
254 * first case, <pool_type> is updated to point to the
255 * next element in the list.
256 */
257#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100258 void *__p; \
259 if ((__p = pool_##type) == NULL) \
260 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100261 else { \
262 pool_##type = *(void **)pool_##type; \
263 } \
willy tarreau4302f492005-12-18 01:00:37 +0100264 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100265})
266
267/*
268 * Puts a memory area back to the corresponding pool.
269 * Items are chained directly through a pointer that
270 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100271 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100272 * that each memory area is at least as big as one
273 * pointer.
274 */
275#define pool_free(type, ptr) ({ \
276 *(void **)ptr = (void *)pool_##type; \
277 pool_##type = (void *)ptr; \
278})
279
280#else
281#define pool_alloc(type) (calloc(1,sizeof_##type));
282#define pool_free(type, ptr) (free(ptr));
283#endif /* MEM_OPTIM */
284
willy tarreau5cbea6f2005-12-17 12:48:26 +0100285#define sizeof_task sizeof(struct task)
286#define sizeof_session sizeof(struct session)
willy tarreau18a957c2006-04-12 19:26:23 +0200287#define sizeof_pendconn sizeof(struct pendconn)
willy tarreau0f7af912005-12-17 12:21:26 +0100288#define sizeof_buffer sizeof(struct buffer)
289#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100290#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100291#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100292#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100293#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100294
willy tarreau5cbea6f2005-12-17 12:48:26 +0100295/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100296#define FD_STCLOSE 0
297#define FD_STLISTEN 1
298#define FD_STCONN 2
299#define FD_STREADY 3
300#define FD_STERROR 4
301
willy tarreau5cbea6f2005-12-17 12:48:26 +0100302/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100303#define TASK_IDLE 0
304#define TASK_RUNNING 1
305
willy tarreau5cbea6f2005-12-17 12:48:26 +0100306/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100307#define PR_STNEW 0
308#define PR_STIDLE 1
309#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100310#define PR_STSTOPPED 3
311#define PR_STPAUSED 4
willy tarreau0f7af912005-12-17 12:21:26 +0100312
willy tarreau5cbea6f2005-12-17 12:48:26 +0100313/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100314#define PR_MODE_TCP 0
315#define PR_MODE_HTTP 1
316#define PR_MODE_HEALTH 2
317
willy tarreau1c2ad212005-12-18 01:11:29 +0100318/* possible actions for the *poll() loops */
319#define POLL_LOOP_ACTION_INIT 0
320#define POLL_LOOP_ACTION_RUN 1
321#define POLL_LOOP_ACTION_CLEAN 2
322
willy tarreau64a3cc32005-12-18 01:13:11 +0100323/* poll mechanisms available */
324#define POLL_USE_SELECT (1<<0)
325#define POLL_USE_POLL (1<<1)
326#define POLL_USE_EPOLL (1<<2)
327
willy tarreau5cbea6f2005-12-17 12:48:26 +0100328/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100329#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
330#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
331#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
332#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
333#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
334#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
335#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
336#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau0174f312005-12-18 01:02:42 +0100337#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
338#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
339#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
340#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
341#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
342#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
343#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
344#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
345#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
346#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
347#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100348#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
349#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100350#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100351#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau1a3442d2006-03-24 21:03:20 +0100352#define PR_O_BALANCE_SH 0x00400000 /* balance on source IP hash */
353#define PR_O_BALANCE (PR_O_BALANCE_RR | PR_O_BALANCE_SH)
willy tarreau5cbea6f2005-12-17 12:48:26 +0100354
willy tarreaua5e8c662006-04-29 10:43:46 +0200355/* various session flags, bits values 0x01 to 0x20 (shift 0) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100356#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
357#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
358#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
359#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
360#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
361#define SN_POST 0x00000020 /* the request was an HTTP POST */
362
willy tarreaua5e8c662006-04-29 10:43:46 +0200363/* session flags dedicated to cookies : bits values 0x40, 0x80 (0-3 shift 6) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100364#define SN_CK_NONE 0x00000000 /* this session had no cookie */
365#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
366#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
367#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
368#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
369#define SN_CK_SHIFT 6 /* bit shift */
370
willy tarreaua5e8c662006-04-29 10:43:46 +0200371/* session termination conditions, bits values 0x100 to 0x700 (0-7 shift 8) */
willy tarreaub1285d52005-12-18 01:20:14 +0100372#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100373#define SN_ERR_CLITO 0x00000100 /* client time-out */
374#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
375#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
376#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
377#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100378#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
379#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100380#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
381#define SN_ERR_SHIFT 8 /* bit shift */
382
willy tarreaua5e8c662006-04-29 10:43:46 +0200383/* session state at termination, bits values 0x1000 to 0x7000 (0-7 shift 12) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100384#define SN_FINST_R 0x00001000 /* session ended during client request */
385#define SN_FINST_C 0x00002000 /* session ended during server connect */
386#define SN_FINST_H 0x00003000 /* session ended during server headers */
387#define SN_FINST_D 0x00004000 /* session ended during data phase */
388#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
willy tarreau078c79a2006-05-13 12:23:58 +0200389#define SN_FINST_Q 0x00006000 /* session ended while waiting in queue for a server slot */
willy tarreau036e1ce2005-12-17 13:46:33 +0100390#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
391#define SN_FINST_SHIFT 12 /* bit shift */
392
willy tarreaua5e8c662006-04-29 10:43:46 +0200393/* cookie information, bits values 0x10000 to 0x80000 (0-8 shift 16) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100394#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
395#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
396#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
397#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
398#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100399#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100400#define SN_SCK_SHIFT 16 /* bit shift */
401
willy tarreaua5e8c662006-04-29 10:43:46 +0200402/* cacheability management, bits values 0x100000 to 0x300000 (0-3 shift 20) */
willy tarreau97f58572005-12-18 00:53:44 +0100403#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
404#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
405#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100406
willy tarreaua5e8c662006-04-29 10:43:46 +0200407/* various other session flags, bits values 0x400000 and above */
408#define SN_MONITOR 0x00400000 /* this session comes from a monitoring system */
willy tarreaudfece232006-05-02 00:19:57 +0200409#define SN_ASSIGNED 0x00800000 /* no need to assign a server to this session */
410#define SN_ADDR_SET 0x01000000 /* this session's server address has been set */
willy tarreaua5e8c662006-04-29 10:43:46 +0200411
412
willy tarreau5cbea6f2005-12-17 12:48:26 +0100413/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100414#define CL_STHEADERS 0
415#define CL_STDATA 1
416#define CL_STSHUTR 2
417#define CL_STSHUTW 3
418#define CL_STCLOSE 4
419
willy tarreau5cbea6f2005-12-17 12:48:26 +0100420/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100421#define SV_STIDLE 0
willy tarreau9fea1942006-05-12 19:46:40 +0200422#define SV_STCONN 1
423#define SV_STHEADERS 2
424#define SV_STDATA 3
425#define SV_STSHUTR 4
426#define SV_STSHUTW 5
427#define SV_STCLOSE 6
willy tarreau0f7af912005-12-17 12:21:26 +0100428
429/* result of an I/O event */
430#define RES_SILENT 0 /* didn't happen */
431#define RES_DATA 1 /* data were sent or received */
432#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
433#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
434
willy tarreau9fe663a2005-12-17 13:02:59 +0100435/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100436#define MODE_DEBUG 1
437#define MODE_STATS 2
438#define MODE_LOG 4
439#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100440#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100441#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100442#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100443#define MODE_STARTING 128
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100444#define MODE_FOREGROUND 256
willy tarreau5cbea6f2005-12-17 12:48:26 +0100445
446/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100447#define SRV_RUNNING 1 /* the server is UP */
448#define SRV_BACKUP 2 /* this server is a backup server */
449#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100450#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100451#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100452
willy tarreaudfece232006-05-02 00:19:57 +0200453/* function which act on servers need to return various errors */
454#define SRV_STATUS_OK 0 /* everything is OK. */
455#define SRV_STATUS_INTERNAL 1 /* other unrecoverable errors. */
456#define SRV_STATUS_NOSRV 2 /* no server is available */
457#define SRV_STATUS_FULL 3 /* the/all server(s) are saturated */
458#define SRV_STATUS_QUEUED 4 /* the/all server(s) are saturated but the connection was queued */
459
willy tarreaue39cd132005-12-17 13:00:18 +0100460/* what to do when a header matches a regex */
461#define ACT_ALLOW 0 /* allow the request */
462#define ACT_REPLACE 1 /* replace the matching header */
463#define ACT_REMOVE 2 /* remove the matching header */
464#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100465#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100466
willy tarreau9fe663a2005-12-17 13:02:59 +0100467/* configuration sections */
468#define CFG_NONE 0
469#define CFG_GLOBAL 1
470#define CFG_LISTEN 2
471
willy tarreaua1598082005-12-17 13:08:06 +0100472/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100473#define LW_DATE 1 /* date */
474#define LW_CLIP 2 /* CLient IP */
475#define LW_SVIP 4 /* SerVer IP */
476#define LW_SVID 8 /* server ID */
477#define LW_REQ 16 /* http REQuest */
478#define LW_RESP 32 /* http RESPonse */
479#define LW_PXIP 64 /* proxy IP */
480#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100481#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100482#define LW_COOKIE 512 /* captured cookie */
483#define LW_REQHDR 1024 /* request header(s) */
484#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100485
willy tarreau41310e72006-03-25 18:17:56 +0100486#define ERR_NONE 0 /* no error */
487#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
488#define ERR_FATAL 2 /* fatal error, may be cumulated */
489
willy tarreau0f7af912005-12-17 12:21:26 +0100490/*********************************************************************/
491
492#define LIST_HEAD(a) ((void *)(&(a)))
493
494/*********************************************************************/
495
willy tarreau4302f492005-12-18 01:00:37 +0100496struct cap_hdr {
497 struct cap_hdr *next;
498 char *name; /* header name, case insensitive */
499 int namelen; /* length of the header name, to speed-up lookups */
500 int len; /* capture length, not including terminal zero */
501 int index; /* index in the output array */
502 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
503};
504
willy tarreau0f7af912005-12-17 12:21:26 +0100505struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100506 struct hdr_exp *next;
507 regex_t *preg; /* expression to look for */
508 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
509 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100510};
511
512struct buffer {
513 unsigned int l; /* data length */
514 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100515 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100516 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100517 char data[BUFSIZE];
518};
519
willy tarreau18a957c2006-04-12 19:26:23 +0200520struct pendconn {
521 struct list list; /* chaining ... */
522 struct session *sess; /* the session waiting for a connection */
523 struct server *srv; /* the server we are waiting for */
524};
525
willy tarreau0f7af912005-12-17 12:21:26 +0100526struct server {
527 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100528 int state; /* server state (SRV_*) */
529 int cklen; /* the len of the cookie, to speed up checks */
530 char *cookie; /* the id set in the cookie */
531 char *id; /* just for identification */
willy tarreau18a957c2006-04-12 19:26:23 +0200532 struct list pendconns; /* pending connections */
533 int nbpend; /* number of pending connections */
willy tarreau59a6cc22006-05-12 01:29:08 +0200534 struct task *queue_mgt; /* the task associated to the queue processing */
willy tarreau0f7af912005-12-17 12:21:26 +0100535 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100536 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100537 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100538 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100539 int rise, fall; /* time in iterations */
540 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100541 int result; /* 0 = connect OK, -1 = connect KO */
542 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreaue3f023f2006-04-08 21:52:24 +0200543 unsigned char uweight, eweight; /* user-specified weight-1, and effective weight-1 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200544 unsigned int wscore; /* weight score, used during srv map computation */
willy tarreaua647c702006-04-15 22:45:52 +0200545 int cur_sess; /* number of currently active sessions (including syn_sent) */
546 unsigned int cum_sess; /* cumulated number of sessions really sent to this server */
willy tarreau18a957c2006-04-12 19:26:23 +0200547 unsigned int maxconn; /* max # of active sessions. 0 = unlimited. */
willy tarreau535ae7a2005-12-17 12:58:00 +0100548 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100549};
550
willy tarreau5cbea6f2005-12-17 12:48:26 +0100551/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100552struct task {
553 struct task *next, *prev; /* chaining ... */
554 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100555 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100556 int state; /* task state : IDLE or RUNNING */
557 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100558 int (*process)(struct task *t); /* the function which processes the task */
559 void *context; /* the task's context */
560};
561
562/* WARNING: if new fields are added, they must be initialized in event_accept() */
563struct session {
564 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100565 /* application specific below */
566 struct timeval crexpire; /* expiration date for a client read */
567 struct timeval cwexpire; /* expiration date for a client write */
568 struct timeval srexpire; /* expiration date for a server read */
569 struct timeval swexpire; /* expiration date for a server write */
570 struct timeval cnexpire; /* expiration date for a connect */
571 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
572 struct proxy *proxy; /* the proxy this socket belongs to */
573 int cli_fd; /* the client side fd */
574 int srv_fd; /* the server side fd */
575 int cli_state; /* state of the client side */
576 int srv_state; /* state of the server side */
577 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100578 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100579 struct buffer *req; /* request buffer */
580 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100581 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100582 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100583 struct server *srv; /* the server being used */
willy tarreau18a957c2006-04-12 19:26:23 +0200584 struct pendconn *pend_pos; /* if not NULL, points to the position in the pending queue */
willy tarreau4302f492005-12-18 01:00:37 +0100585 char **req_cap; /* array of captured request headers (may be NULL) */
586 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100587 struct {
588 int logwait; /* log fields waiting to be collected : LW_* */
589 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
590 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
willy tarreauf32f5242006-05-02 22:54:52 +0200591 long t_queue; /* delay before the session gets out of the connect queue, -1 if never occurs */
willy tarreaua1598082005-12-17 13:08:06 +0100592 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
593 long t_data; /* delay before the first data byte from the server ... */
594 unsigned long t_close; /* total session duration */
willy tarreau5e69b162006-05-12 19:49:37 +0200595 unsigned long srv_queue_size; /* number of sessions waiting for a connect slot on this server at accept() time (in direct assignment) */
596 unsigned long prx_queue_size; /* overall number of sessions waiting for a connect slot on this instance at accept() time */
willy tarreaua1598082005-12-17 13:08:06 +0100597 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100598 char *cli_cookie; /* cookie presented by the client, in capture mode */
599 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100600 int status; /* HTTP status from the server, negative if from proxy */
601 long long bytes; /* number of bytes transferred from the server */
602 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100603 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100604};
605
willy tarreaua41a8b42005-12-17 14:02:24 +0100606struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100607 int fd; /* the listen socket */
608 struct sockaddr_storage addr; /* the address we listen to */
609 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100610};
willy tarreauf32f5242006-05-02 22:54:52 +0200611
willy tarreau0f7af912005-12-17 12:21:26 +0100612struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100613 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100614 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 +0100615 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100616 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200617 struct server *srv; /* known servers */
618 int srv_act, srv_bck; /* # of running servers */
619 int tot_wact, tot_wbck; /* total weights of active and backup servers */
620 struct server **srv_map; /* the server map used to apply weights */
621 int srv_map_sz; /* the size of the effective server map */
622 int srv_rr_idx; /* next server to be elected in round robin mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100623 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100624 int cookie_len; /* strlen(cookie_name), computed only once */
625 char *appsession_name; /* name of the cookie to look for */
626 int appsession_name_len; /* strlen(appsession_name), computed only once */
627 int appsession_len; /* length of the appsession cookie value to be used */
628 int appsession_timeout;
629 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100630 char *capture_name; /* beginning of the name of the cookie to capture */
631 int capture_namelen; /* length of the cookie name to match */
632 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100633 int clitimeout; /* client I/O timeout (in milliseconds) */
634 int srvtimeout; /* server I/O timeout (in milliseconds) */
635 int contimeout; /* connect timeout (in milliseconds) */
636 char *id; /* proxy id */
willy tarreaudfece232006-05-02 00:19:57 +0200637 struct list pendconns; /* pending connections with no server assigned yet */
638 int nbpend; /* number of pending connections with no server assigned yet */
willy tarreauf32f5242006-05-02 22:54:52 +0200639 int totpend; /* total number of pending connections on this instance (for stats) */
willy tarreau0f7af912005-12-17 12:21:26 +0100640 int nbconn; /* # of active sessions */
willy tarreau14b4d432006-04-07 18:23:29 +0200641 unsigned int cum_conn; /* cumulated number of processed sessions */
willy tarreau0f7af912005-12-17 12:21:26 +0100642 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100643 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100644 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100645 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100646 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100647 struct proxy *next;
648 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100649 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100650 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100651 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100652 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100653 int nb_reqadd, nb_rspadd;
654 struct hdr_exp *req_exp; /* regular expressions for request headers */
655 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100656 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
657 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
658 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
659 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100660 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100661 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100662 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
663 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100664 struct {
665 char *msg400; /* message for error 400 */
666 int len400; /* message length for error 400 */
667 char *msg403; /* message for error 403 */
668 int len403; /* message length for error 403 */
669 char *msg408; /* message for error 408 */
670 int len408; /* message length for error 408 */
671 char *msg500; /* message for error 500 */
672 int len500; /* message length for error 500 */
673 char *msg502; /* message for error 502 */
674 int len502; /* message length for error 502 */
675 char *msg503; /* message for error 503 */
676 int len503; /* message length for error 503 */
677 char *msg504; /* message for error 504 */
678 int len504; /* message length for error 504 */
679 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100680};
681
682/* info about one given fd */
683struct fdtab {
684 int (*read)(int fd); /* read function */
685 int (*write)(int fd); /* write function */
686 struct task *owner; /* the session (or proxy) associated with this fd */
687 int state; /* the state of this fd */
688};
689
690/*********************************************************************/
691
willy tarreaub952e1d2005-12-18 01:31:20 +0100692int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100693int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100694char *cfg_cfgfile = NULL; /* configuration file */
695char *progname = NULL; /* program name */
696int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100697
698/* global options */
699static struct {
700 int uid;
701 int gid;
702 int nbproc;
703 int maxconn;
704 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100705 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100706 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100707 int mode;
708 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100709 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100710 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100711 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100712 struct sockaddr_in logsrv1, logsrv2;
713} global = {
714 logfac1 : -1,
715 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100716 loglev1 : 7, /* max syslog level : debug */
717 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100718 /* others NULL OK */
719};
720
willy tarreau0f7af912005-12-17 12:21:26 +0100721/*********************************************************************/
722
willy tarreau1c2ad212005-12-18 01:11:29 +0100723fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100724 *StaticWriteEvent;
725
willy tarreau64a3cc32005-12-18 01:13:11 +0100726int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100727
willy tarreau0f7af912005-12-17 12:21:26 +0100728void **pool_session = NULL,
willy tarreau18a957c2006-04-12 19:26:23 +0200729 **pool_pendconn = NULL,
willy tarreau0f7af912005-12-17 12:21:26 +0100730 **pool_buffer = NULL,
731 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100732 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100733 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100734 **pool_capture = NULL,
735 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100736
737struct proxy *proxy = NULL; /* list of all existing proxies */
738struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100739struct task *rq = NULL; /* global run queue */
willy tarreau5e698ef2006-05-02 14:51:00 +0200740struct task wait_queue[2] = { /* global wait queue */
741 {
742 prev:LIST_HEAD(wait_queue[0]), /* expirable tasks */
743 next:LIST_HEAD(wait_queue[0]),
744 },
745 {
746 prev:LIST_HEAD(wait_queue[1]), /* non-expirable tasks */
747 next:LIST_HEAD(wait_queue[1]),
748 },
willy tarreau5cbea6f2005-12-17 12:48:26 +0100749};
willy tarreau0f7af912005-12-17 12:21:26 +0100750
willy tarreau0f7af912005-12-17 12:21:26 +0100751static int totalconn = 0; /* total # of terminated sessions */
752static int actconn = 0; /* # of active sessions */
753static int maxfd = 0; /* # of the highest fd + 1 */
754static int listeners = 0; /* # of listeners */
755static int stopping = 0; /* non zero means stopping in progress */
756static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100757static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100758
willy tarreau53e99702006-03-25 18:53:50 +0100759/* Here we store informations about the pids of the processes we may pause
760 * or kill. We will send them a signal every 10 ms until we can bind to all
761 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100762 */
willy tarreau53e99702006-03-25 18:53:50 +0100763#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100764static int nb_oldpids = 0;
765static int *oldpids = NULL;
766static int oldpids_sig; /* use USR1 or TERM */
767
willy tarreau08dedbe2005-12-18 01:13:48 +0100768#if defined(ENABLE_EPOLL)
769/* FIXME: this is dirty, but at the moment, there's no other solution to remove
770 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
771 * structure with pointers to functions such as init_fd() and close_fd(), plus
772 * a private structure with several pointers to places such as below.
773 */
774
775static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
776#endif
777
willy tarreau0f7af912005-12-17 12:21:26 +0100778static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100779/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100780static char trash[BUFSIZE];
781
willy tarreaudd07e972005-12-18 00:48:48 +0100782const int zero = 0;
783const int one = 1;
784
willy tarreau0f7af912005-12-17 12:21:26 +0100785/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100786 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100787 */
788
789#define MAX_SYSLOG_LEN 1024
790#define NB_LOG_FACILITIES 24
791const char *log_facilities[NB_LOG_FACILITIES] = {
792 "kern", "user", "mail", "daemon",
793 "auth", "syslog", "lpr", "news",
794 "uucp", "cron", "auth2", "ftp",
795 "ntp", "audit", "alert", "cron2",
796 "local0", "local1", "local2", "local3",
797 "local4", "local5", "local6", "local7"
798};
799
800
801#define NB_LOG_LEVELS 8
802const char *log_levels[NB_LOG_LEVELS] = {
803 "emerg", "alert", "crit", "err",
804 "warning", "notice", "info", "debug"
805};
806
807#define SYSLOG_PORT 514
808
809const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
810 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100811
willy tarreaub1285d52005-12-18 01:20:14 +0100812const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau078c79a2006-05-13 12:23:58 +0200813const char sess_fin_state[8] = "-RCHDLQ7"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, unknown */
willy tarreau036e1ce2005-12-17 13:46:33 +0100814const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
815const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
816 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
817 unknown, Set-cookie Rewritten */
818
willy tarreau0f7af912005-12-17 12:21:26 +0100819#define MAX_HOSTNAME_LEN 32
820static char hostname[MAX_HOSTNAME_LEN] = "";
821
willy tarreau8337c6b2005-12-17 13:41:01 +0100822const char *HTTP_302 =
823 "HTTP/1.0 302 Found\r\n"
824 "Cache-Control: no-cache\r\n"
825 "Connection: close\r\n"
826 "Location: "; /* not terminated since it will be concatenated with the URL */
827
willy tarreauc1f47532005-12-18 01:08:26 +0100828/* same as 302 except that the browser MUST retry with the GET method */
829const char *HTTP_303 =
830 "HTTP/1.0 303 See Other\r\n"
831 "Cache-Control: no-cache\r\n"
832 "Connection: close\r\n"
833 "Location: "; /* not terminated since it will be concatenated with the URL */
834
willy tarreaua1598082005-12-17 13:08:06 +0100835const char *HTTP_400 =
836 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100837 "Cache-Control: no-cache\r\n"
838 "Connection: close\r\n"
839 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100840 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100841
willy tarreaua1598082005-12-17 13:08:06 +0100842const char *HTTP_403 =
843 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100844 "Cache-Control: no-cache\r\n"
845 "Connection: close\r\n"
846 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100847 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
848
willy tarreau8337c6b2005-12-17 13:41:01 +0100849const char *HTTP_408 =
850 "HTTP/1.0 408 Request Time-out\r\n"
851 "Cache-Control: no-cache\r\n"
852 "Connection: close\r\n"
853 "\r\n"
854 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
855
willy tarreau750a4722005-12-17 13:21:24 +0100856const char *HTTP_500 =
857 "HTTP/1.0 500 Server Error\r\n"
858 "Cache-Control: no-cache\r\n"
859 "Connection: close\r\n"
860 "\r\n"
861 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100862
863const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100864 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100865 "Cache-Control: no-cache\r\n"
866 "Connection: close\r\n"
867 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100868 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
869
870const char *HTTP_503 =
871 "HTTP/1.0 503 Service Unavailable\r\n"
872 "Cache-Control: no-cache\r\n"
873 "Connection: close\r\n"
874 "\r\n"
875 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
876
877const char *HTTP_504 =
878 "HTTP/1.0 504 Gateway Time-out\r\n"
879 "Cache-Control: no-cache\r\n"
880 "Connection: close\r\n"
881 "\r\n"
882 "<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 +0100883
willy tarreau0f7af912005-12-17 12:21:26 +0100884/*********************************************************************/
885/* statistics ******************************************************/
886/*********************************************************************/
887
willy tarreau750a4722005-12-17 13:21:24 +0100888#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100889static int stats_tsk_lsrch, stats_tsk_rsrch,
890 stats_tsk_good, stats_tsk_right, stats_tsk_left,
891 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100892#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100893
894
895/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100896/* debugging *******************************************************/
897/*********************************************************************/
898#ifdef DEBUG_FULL
899static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau18a957c2006-04-12 19:26:23 +0200900static char *srv_stnames[8] = {"IDL", "PND", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau750a4722005-12-17 13:21:24 +0100901#endif
902
903/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100904/* function prototypes *********************************************/
905/*********************************************************************/
906
907int event_accept(int fd);
908int event_cli_read(int fd);
909int event_cli_write(int fd);
910int event_srv_read(int fd);
911int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100912int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100913
willy tarreau12350152005-12-18 01:03:27 +0100914static int appsession_task_init(void);
915static int appsession_init(void);
916static int appsession_refresh(struct task *t);
917
willy tarreau0f7af912005-12-17 12:21:26 +0100918/*********************************************************************/
919/* general purpose functions ***************************************/
920/*********************************************************************/
921
922void display_version() {
923 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100924 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100925}
926
927/*
928 * This function prints the command line usage and exits
929 */
930void usage(char *name) {
931 display_version();
932 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100933 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100934#if STATTIME > 0
935 "sl"
936#endif
willy tarreau746e26b2006-03-25 11:14:35 +0100937 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
938 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100939 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100940 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +0100941 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100942#if STATTIME > 0
943 " -s enables statistics output\n"
944 " -l enables long statistics format\n"
945#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100946 " -D goes daemon ; implies -q\n"
947 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100948 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100949 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +0100950 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100951 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100952 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100953#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100954 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100955#endif
956#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100957 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100958#endif
willy tarreau53e99702006-03-25 18:53:50 +0100959 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100960 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100961 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100962 exit(1);
963}
964
965
966/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100967 * Displays the message on stderr with the date and pid. Overrides the quiet
968 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100969 */
970void Alert(char *fmt, ...) {
971 va_list argp;
972 struct timeval tv;
973 struct tm *tm;
974
willy tarreaud0fb4652005-12-18 01:32:04 +0100975 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100976 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100977
willy tarreau5cbea6f2005-12-17 12:48:26 +0100978 gettimeofday(&tv, NULL);
979 tm=localtime(&tv.tv_sec);
980 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100981 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100982 vfprintf(stderr, fmt, argp);
983 fflush(stderr);
984 va_end(argp);
985 }
willy tarreau0f7af912005-12-17 12:21:26 +0100986}
987
988
989/*
990 * Displays the message on stderr with the date and pid.
991 */
992void Warning(char *fmt, ...) {
993 va_list argp;
994 struct timeval tv;
995 struct tm *tm;
996
willy tarreau982249e2005-12-18 00:57:06 +0100997 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100998 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100999
willy tarreau5cbea6f2005-12-17 12:48:26 +01001000 gettimeofday(&tv, NULL);
1001 tm=localtime(&tv.tv_sec);
1002 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001003 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001004 vfprintf(stderr, fmt, argp);
1005 fflush(stderr);
1006 va_end(argp);
1007 }
1008}
1009
1010/*
1011 * Displays the message on <out> only if quiet mode is not set.
1012 */
1013void qfprintf(FILE *out, char *fmt, ...) {
1014 va_list argp;
1015
willy tarreau982249e2005-12-18 00:57:06 +01001016 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001017 va_start(argp, fmt);
1018 vfprintf(out, fmt, argp);
1019 fflush(out);
1020 va_end(argp);
1021 }
willy tarreau0f7af912005-12-17 12:21:26 +01001022}
1023
1024
1025/*
1026 * converts <str> to a struct sockaddr_in* which is locally allocated.
1027 * The format is "addr:port", where "addr" can be empty or "*" to indicate
1028 * INADDR_ANY.
1029 */
1030struct sockaddr_in *str2sa(char *str) {
1031 static struct sockaddr_in sa;
1032 char *c;
1033 int port;
1034
willy tarreaua1598082005-12-17 13:08:06 +01001035 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +01001036 str=strdup(str);
1037
1038 if ((c=strrchr(str,':')) != NULL) {
1039 *c++=0;
1040 port=atol(c);
1041 }
1042 else
1043 port=0;
1044
1045 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1046 sa.sin_addr.s_addr = INADDR_ANY;
1047 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01001048 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001049 struct hostent *he;
1050
1051 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001052 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001053 }
1054 else
1055 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1056 }
1057 sa.sin_port=htons(port);
1058 sa.sin_family=AF_INET;
1059
1060 free(str);
1061 return &sa;
1062}
1063
willy tarreaub1285d52005-12-18 01:20:14 +01001064/*
1065 * converts <str> to a two struct in_addr* which are locally allocated.
1066 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1067 * is optionnal and either in the dotted or CIDR notation.
1068 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1069 */
1070int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1071 char *c;
1072 unsigned long len;
1073
1074 memset(mask, 0, sizeof(*mask));
1075 memset(addr, 0, sizeof(*addr));
1076 str=strdup(str);
1077
1078 if ((c = strrchr(str, '/')) != NULL) {
1079 *c++ = 0;
1080 /* c points to the mask */
1081 if (strchr(c, '.') != NULL) { /* dotted notation */
1082 if (!inet_pton(AF_INET, c, mask))
1083 return 0;
1084 }
1085 else { /* mask length */
1086 char *err;
1087 len = strtol(c, &err, 10);
1088 if (!*c || (err && *err) || (unsigned)len > 32)
1089 return 0;
1090 if (len)
1091 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1092 else
1093 mask->s_addr = 0;
1094 }
1095 }
1096 else {
1097 mask->s_addr = 0xFFFFFFFF;
1098 }
1099 if (!inet_pton(AF_INET, str, addr)) {
1100 struct hostent *he;
1101
1102 if ((he = gethostbyname(str)) == NULL) {
1103 return 0;
1104 }
1105 else
1106 *addr = *(struct in_addr *) *(he->h_addr_list);
1107 }
1108 free(str);
1109 return 1;
1110}
1111
willy tarreau9fe663a2005-12-17 13:02:59 +01001112
1113/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001114 * converts <str> to a list of listeners which are dynamically allocated.
1115 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1116 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1117 * - <port> is a numerical port from 1 to 65535 ;
1118 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1119 * This can be repeated as many times as necessary, separated by a coma.
1120 * The <tail> argument is a pointer to a current list which should be appended
1121 * to the tail of the new list. The pointer to the new list is returned.
1122 */
1123struct listener *str2listener(char *str, struct listener *tail) {
1124 struct listener *l;
1125 char *c, *next, *range, *dupstr;
1126 int port, end;
1127
1128 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001129
willy tarreaua41a8b42005-12-17 14:02:24 +01001130 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001131 struct sockaddr_storage ss;
1132
willy tarreaua41a8b42005-12-17 14:02:24 +01001133 str = next;
1134 /* 1) look for the end of the first address */
1135 if ((next = strrchr(str, ',')) != NULL) {
1136 *next++ = 0;
1137 }
1138
willy tarreau8a86dbf2005-12-18 00:45:59 +01001139 /* 2) look for the addr/port delimiter, it's the last colon. */
1140 if ((range = strrchr(str, ':')) == NULL) {
1141 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001142 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001143 }
1144
1145 *range++ = 0;
1146
1147 if (strrchr(str, ':') != NULL) {
1148 /* IPv6 address contains ':' */
1149 memset(&ss, 0, sizeof(ss));
1150 ss.ss_family = AF_INET6;
1151
1152 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1153 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001154 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001155 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001156 }
1157 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001158 memset(&ss, 0, sizeof(ss));
1159 ss.ss_family = AF_INET;
1160
1161 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1162 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1163 }
1164 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1165 struct hostent *he;
1166
1167 if ((he = gethostbyname(str)) == NULL) {
1168 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001169 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001170 }
1171 else
1172 ((struct sockaddr_in *)&ss)->sin_addr =
1173 *(struct in_addr *) *(he->h_addr_list);
1174 }
1175 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001176
1177 /* 3) look for the port-end delimiter */
1178 if ((c = strchr(range, '-')) != NULL) {
1179 *c++ = 0;
1180 end = atol(c);
1181 }
1182 else {
1183 end = atol(range);
1184 }
1185
willy tarreaud0fb4652005-12-18 01:32:04 +01001186 port = atol(range);
1187
1188 if (port < 1 || port > 65535) {
1189 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1190 goto fail;
1191 }
1192
1193 if (end < 1 || end > 65535) {
1194 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1195 goto fail;
1196 }
1197
1198 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001199 l = (struct listener *)calloc(1, sizeof(struct listener));
1200 l->next = tail;
1201 tail = l;
1202
willy tarreau41310e72006-03-25 18:17:56 +01001203 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001204 l->addr = ss;
1205 if (ss.ss_family == AF_INET6)
1206 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1207 else
1208 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1209
willy tarreaua41a8b42005-12-17 14:02:24 +01001210 } /* end for(port) */
1211 } /* end while(next) */
1212 free(dupstr);
1213 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001214 fail:
1215 free(dupstr);
1216 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001217}
1218
willy tarreau4302f492005-12-18 01:00:37 +01001219
1220#define FD_SETS_ARE_BITFIELDS
1221#ifdef FD_SETS_ARE_BITFIELDS
1222/*
1223 * This map is used with all the FD_* macros to check whether a particular bit
1224 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1225 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1226 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1227 * exclusively to the macros.
1228 */
1229fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1230fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1231
1232#else
1233#error "Check if your OS uses bitfields for fd_sets"
1234#endif
1235
1236/* will try to encode the string <string> replacing all characters tagged in
1237 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1238 * prefixed by <escape>, and will store the result between <start> (included
1239 *) and <stop> (excluded), and will always terminate the string with a '\0'
1240 * before <stop>. The position of the '\0' is returned if the conversion
1241 * completes. If bytes are missing between <start> and <stop>, then the
1242 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1243 * cannot even be stored so we return <start> without writing the 0.
1244 * The input string must also be zero-terminated.
1245 */
1246char hextab[16] = "0123456789ABCDEF";
1247char *encode_string(char *start, char *stop,
1248 const char escape, const fd_set *map,
1249 const char *string)
1250{
1251 if (start < stop) {
1252 stop--; /* reserve one byte for the final '\0' */
1253 while (start < stop && *string != 0) {
1254 if (!FD_ISSET((unsigned char)(*string), map))
1255 *start++ = *string;
1256 else {
1257 if (start + 3 >= stop)
1258 break;
1259 *start++ = escape;
1260 *start++ = hextab[(*string >> 4) & 15];
1261 *start++ = hextab[*string & 15];
1262 }
1263 string++;
1264 }
1265 *start = '\0';
1266 }
1267 return start;
1268}
willy tarreaua41a8b42005-12-17 14:02:24 +01001269
1270/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001271 * This function sends a syslog message to both log servers of a proxy,
1272 * or to global log servers if the proxy is NULL.
1273 * It also tries not to waste too much time computing the message header.
1274 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001275 */
1276void send_log(struct proxy *p, int level, char *message, ...) {
1277 static int logfd = -1; /* syslog UDP socket */
1278 static long tvsec = -1; /* to force the string to be initialized */
1279 struct timeval tv;
1280 va_list argp;
1281 static char logmsg[MAX_SYSLOG_LEN];
1282 static char *dataptr = NULL;
1283 int fac_level;
1284 int hdr_len, data_len;
1285 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001286 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001287 int nbloggers = 0;
1288 char *log_ptr;
1289
1290 if (logfd < 0) {
1291 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1292 return;
1293 }
1294
1295 if (level < 0 || progname == NULL || message == NULL)
1296 return;
1297
1298 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001299 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001300 /* this string is rebuild only once a second */
1301 struct tm *tm = localtime(&tv.tv_sec);
1302 tvsec = tv.tv_sec;
1303
willy tarreauc29948c2005-12-17 13:10:27 +01001304 hdr_len = snprintf(logmsg, sizeof(logmsg),
1305 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1306 monthname[tm->tm_mon],
1307 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1308 progname, pid);
1309 /* WARNING: depending upon implementations, snprintf may return
1310 * either -1 or the number of bytes that would be needed to store
1311 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001312 */
willy tarreauc29948c2005-12-17 13:10:27 +01001313 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1314 hdr_len = sizeof(logmsg);
1315
1316 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001317 }
1318
1319 va_start(argp, message);
1320 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001321 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1322 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001323 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001324 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001325
1326 if (p == NULL) {
1327 if (global.logfac1 >= 0) {
1328 sa[nbloggers] = &global.logsrv1;
1329 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001330 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001331 nbloggers++;
1332 }
1333 if (global.logfac2 >= 0) {
1334 sa[nbloggers] = &global.logsrv2;
1335 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001336 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001337 nbloggers++;
1338 }
1339 } else {
1340 if (p->logfac1 >= 0) {
1341 sa[nbloggers] = &p->logsrv1;
1342 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001343 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001344 nbloggers++;
1345 }
1346 if (p->logfac2 >= 0) {
1347 sa[nbloggers] = &p->logsrv2;
1348 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001349 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001350 nbloggers++;
1351 }
1352 }
1353
1354 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001355 /* we can filter the level of the messages that are sent to each logger */
1356 if (level > loglevel[nbloggers])
1357 continue;
1358
willy tarreauc29948c2005-12-17 13:10:27 +01001359 /* For each target, we may have a different facility.
1360 * We can also have a different log level for each message.
1361 * This induces variations in the message header length.
1362 * Since we don't want to recompute it each time, nor copy it every
1363 * time, we only change the facility in the pre-computed header,
1364 * and we change the pointer to the header accordingly.
1365 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001366 fac_level = (facilities[nbloggers] << 3) + level;
1367 log_ptr = logmsg + 3; /* last digit of the log level */
1368 do {
1369 *log_ptr = '0' + fac_level % 10;
1370 fac_level /= 10;
1371 log_ptr--;
1372 } while (fac_level && log_ptr > logmsg);
1373 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001374
willy tarreauc29948c2005-12-17 13:10:27 +01001375 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001376
1377#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001378 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001379 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1380#else
willy tarreauc29948c2005-12-17 13:10:27 +01001381 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001382 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1383#endif
1384 }
willy tarreau0f7af912005-12-17 12:21:26 +01001385}
1386
1387
1388/* sets <tv> to the current time */
1389static inline struct timeval *tv_now(struct timeval *tv) {
1390 if (tv)
1391 gettimeofday(tv, NULL);
1392 return tv;
1393}
1394
1395/*
1396 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1397 */
willy tarreaudab722b2006-05-04 19:23:38 +02001398static struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
willy tarreau0f7af912005-12-17 12:21:26 +01001399 if (!tv || !from)
1400 return NULL;
1401 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1402 tv->tv_sec = from->tv_sec + (ms/1000);
1403 while (tv->tv_usec >= 1000000) {
1404 tv->tv_usec -= 1000000;
1405 tv->tv_sec++;
1406 }
1407 return tv;
1408}
1409
1410/*
1411 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001412 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001413 */
1414static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001415 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001416 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001417 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001418 return 1;
1419 else if (tv1->tv_usec < tv2->tv_usec)
1420 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001421 else if (tv1->tv_usec > tv2->tv_usec)
1422 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001423 else
1424 return 0;
1425}
1426
1427/*
1428 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001429 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001430 */
1431unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1432 int cmp;
1433 unsigned long ret;
1434
1435
willy tarreauef900ab2005-12-17 12:52:52 +01001436 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001437 if (!cmp)
1438 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001439 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001440 struct timeval *tmp = tv1;
1441 tv1 = tv2;
1442 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001443 }
willy tarreauef900ab2005-12-17 12:52:52 +01001444 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001445 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001446 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001447 else
willy tarreauef900ab2005-12-17 12:52:52 +01001448 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001449 return (unsigned long) ret;
1450}
1451
1452/*
willy tarreau750a4722005-12-17 13:21:24 +01001453 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001454 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001455 */
1456static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1457 unsigned long ret;
1458
willy tarreau6e682ce2005-12-17 13:26:49 +01001459 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1460 if (tv2->tv_usec > tv1->tv_usec)
1461 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001462 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001463 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001464 return (unsigned long) ret;
1465}
1466
1467/*
willy tarreau0f7af912005-12-17 12:21:26 +01001468 * 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 +01001469 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001470 */
willy tarreaudab722b2006-05-04 19:23:38 +02001471static int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001472 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001473 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001474 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001475 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001476 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001477 else
1478 return 0;
1479 }
willy tarreau0f7af912005-12-17 12:21:26 +01001480 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001481 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001482 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001483 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001484 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001485 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001486 else
1487 return 0;
1488}
1489
1490/*
1491 * returns the remaining time between tv1=now and event=tv2
1492 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001493 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001494 */
1495static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1496 unsigned long ret;
1497
willy tarreau0f7af912005-12-17 12:21:26 +01001498 if (tv_cmp_ms(tv1, tv2) >= 0)
1499 return 0; /* event elapsed */
1500
willy tarreauef900ab2005-12-17 12:52:52 +01001501 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001502 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001503 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001504 else
willy tarreauef900ab2005-12-17 12:52:52 +01001505 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001506 return (unsigned long) ret;
1507}
1508
1509
1510/*
1511 * zeroes a struct timeval
1512 */
1513
1514static inline struct timeval *tv_eternity(struct timeval *tv) {
1515 tv->tv_sec = tv->tv_usec = 0;
1516 return tv;
1517}
1518
1519/*
1520 * returns 1 if tv is null, else 0
1521 */
1522static inline int tv_iseternity(struct timeval *tv) {
1523 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1524 return 1;
1525 else
1526 return 0;
1527}
1528
1529/*
1530 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1531 * considering that 0 is the eternity.
1532 */
willy tarreaudab722b2006-05-04 19:23:38 +02001533static int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001534 if (tv_iseternity(tv1))
1535 if (tv_iseternity(tv2))
1536 return 0; /* same */
1537 else
1538 return 1; /* tv1 later than tv2 */
1539 else if (tv_iseternity(tv2))
1540 return -1; /* tv2 later than tv1 */
1541
1542 if (tv1->tv_sec > tv2->tv_sec)
1543 return 1;
1544 else if (tv1->tv_sec < tv2->tv_sec)
1545 return -1;
1546 else if (tv1->tv_usec > tv2->tv_usec)
1547 return 1;
1548 else if (tv1->tv_usec < tv2->tv_usec)
1549 return -1;
1550 else
1551 return 0;
1552}
1553
1554/*
1555 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1556 * considering that 0 is the eternity.
1557 */
willy tarreaudab722b2006-05-04 19:23:38 +02001558static int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001559 if (tv_iseternity(tv1))
1560 if (tv_iseternity(tv2))
1561 return 0; /* same */
1562 else
1563 return 1; /* tv1 later than tv2 */
1564 else if (tv_iseternity(tv2))
1565 return -1; /* tv2 later than tv1 */
1566
willy tarreauefae1842005-12-17 12:51:03 +01001567 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001568 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001569 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001570 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001571 return -1;
1572 else
1573 return 0;
1574 }
1575 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001576 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001577 return 1;
1578 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001579 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001580 return -1;
1581 else
1582 return 0;
1583}
1584
1585/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001586 * returns the remaining time between tv1=now and event=tv2
1587 * if tv2 is passed, 0 is returned.
1588 * Returns TIME_ETERNITY if tv2 is eternity.
1589 */
willy tarreaudab722b2006-05-04 19:23:38 +02001590static unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001591 unsigned long ret;
1592
1593 if (tv_iseternity(tv2))
1594 return TIME_ETERNITY;
1595
1596 if (tv_cmp_ms(tv1, tv2) >= 0)
1597 return 0; /* event elapsed */
1598
1599 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1600 if (tv2->tv_usec > tv1->tv_usec)
1601 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1602 else
1603 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1604 return (unsigned long) ret;
1605}
1606
1607/*
willy tarreau0f7af912005-12-17 12:21:26 +01001608 * returns the first event between tv1 and tv2 into tvmin.
1609 * a zero tv is ignored. tvmin is returned.
1610 */
1611static inline struct timeval *tv_min(struct timeval *tvmin,
1612 struct timeval *tv1, struct timeval *tv2) {
1613
1614 if (tv_cmp2(tv1, tv2) <= 0)
1615 *tvmin = *tv1;
1616 else
1617 *tvmin = *tv2;
1618
1619 return tvmin;
1620}
1621
1622
1623
1624/***********************************************************/
1625/* fd management ***************************************/
1626/***********************************************************/
1627
1628
1629
willy tarreau5cbea6f2005-12-17 12:48:26 +01001630/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1631 * The file descriptor is also closed.
1632 */
willy tarreaudab722b2006-05-04 19:23:38 +02001633static void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001634 FD_CLR(fd, StaticReadEvent);
1635 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001636#if defined(ENABLE_EPOLL)
1637 if (PrevReadEvent) {
1638 FD_CLR(fd, PrevReadEvent);
1639 FD_CLR(fd, PrevWriteEvent);
1640 }
1641#endif
1642
willy tarreau5cbea6f2005-12-17 12:48:26 +01001643 close(fd);
1644 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001645
1646 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1647 maxfd--;
1648}
1649
1650/* recomputes the maxfd limit from the fd */
1651static inline void fd_insert(int fd) {
1652 if (fd+1 > maxfd)
1653 maxfd = fd+1;
1654}
1655
1656/*************************************************************/
1657/* task management ***************************************/
1658/*************************************************************/
1659
willy tarreau5cbea6f2005-12-17 12:48:26 +01001660/* puts the task <t> in run queue <q>, and returns <t> */
1661static inline struct task *task_wakeup(struct task **q, struct task *t) {
1662 if (t->state == TASK_RUNNING)
1663 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001664 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001665 t->rqnext = *q;
1666 t->state = TASK_RUNNING;
1667 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001668 }
1669}
1670
willy tarreau5cbea6f2005-12-17 12:48:26 +01001671/* removes the task <t> from the queue <q>
1672 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001673 * set the run queue to point to the next one, and return it
1674 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001675static inline struct task *task_sleep(struct task **q, struct task *t) {
1676 if (t->state == TASK_RUNNING) {
1677 *q = t->rqnext;
1678 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001679 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001680 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001681}
1682
1683/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001684 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001685 * from the run queue. A pointer to the task itself is returned.
1686 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001687static inline struct task *task_delete(struct task *t) {
1688 t->prev->next = t->next;
1689 t->next->prev = t->prev;
1690 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001691}
1692
1693/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001694 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001695 */
1696static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001697 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001698}
1699
willy tarreau5cbea6f2005-12-17 12:48:26 +01001700/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001701 * may be only moved or left where it was, depending on its timing requirements.
1702 * <task> is returned.
1703 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001704struct task *task_queue(struct task *task) {
1705 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001706 struct task *start_from;
1707
willy tarreau5e698ef2006-05-02 14:51:00 +02001708 /* This is a very dirty hack to queue non-expirable tasks in another queue
1709 * in order to avoid pulluting the tail of the standard queue. This will go
1710 * away with the new O(log(n)) scheduler anyway.
1711 */
1712 if (tv_iseternity(&task->expire)) {
1713 /* if the task was queued in the standard wait queue, we must dequeue it */
1714 if (task->prev) {
1715 if (task->wq == LIST_HEAD(wait_queue[1]))
1716 return task;
1717 else {
1718 task_delete(task);
1719 task->prev = NULL;
1720 }
1721 }
1722 list = task->wq = LIST_HEAD(wait_queue[1]);
1723 } else {
1724 /* if the task was queued in the eternity queue, we must dequeue it */
1725 if (task->prev && (task->wq == LIST_HEAD(wait_queue[1]))) {
1726 task_delete(task);
1727 task->prev = NULL;
1728 list = task->wq = LIST_HEAD(wait_queue[0]);
1729 }
1730 }
1731
1732 /* next, test if the task was already in a list */
willy tarreau0f7af912005-12-17 12:21:26 +01001733 if (task->prev == NULL) {
1734 // start_from = list;
1735 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001736#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001737 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001738#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001739 /* insert the unlinked <task> into the list, searching back from the last entry */
1740 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1741 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001742#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001743 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001744#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001745 }
1746
1747 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1748 // start_from = start_from->next;
1749 // stats_tsk_nsrch++;
1750 // }
1751 }
1752 else if (task->prev == list ||
1753 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1754 start_from = task->next;
1755 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001756#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001757 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001758#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001759 return task; /* it's already in the right place */
1760 }
1761
willy tarreau750a4722005-12-17 13:21:24 +01001762#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001763 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001764#endif
1765
1766 /* if the task is not at the right place, there's little chance that
1767 * it has only shifted a bit, and it will nearly always be queued
1768 * at the end of the list because of constant timeouts
1769 * (observed in real case).
1770 */
1771#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1772 start_from = list->prev; /* assume we'll queue to the end of the list */
1773 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1774 start_from = start_from->prev;
1775#if STATTIME > 0
1776 stats_tsk_lsrch++;
1777#endif
1778 }
1779#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001780 /* insert the unlinked <task> into the list, searching after position <start_from> */
1781 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1782 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001783#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001784 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001785#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001786 }
willy tarreau750a4722005-12-17 13:21:24 +01001787#endif /* WE_REALLY_... */
1788
willy tarreau0f7af912005-12-17 12:21:26 +01001789 /* we need to unlink it now */
1790 task_delete(task);
1791 }
1792 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001793#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001794 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001795#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001796#ifdef LEFT_TO_TOP /* not very good */
1797 start_from = list;
1798 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1799 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001800#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001801 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001802#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001803 }
1804#else
1805 start_from = task->prev->prev; /* valid because of the previous test above */
1806 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1807 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001808#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001809 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001810#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001811 }
1812#endif
1813 /* we need to unlink it now */
1814 task_delete(task);
1815 }
1816 task->prev = start_from;
1817 task->next = start_from->next;
1818 task->next->prev = task;
1819 start_from->next = task;
1820 return task;
1821}
1822
1823
1824/*********************************************************************/
willy tarreau18a957c2006-04-12 19:26:23 +02001825/* pending connections queues **************************************/
1826/*********************************************************************/
1827
1828/*
willy tarreaudfece232006-05-02 00:19:57 +02001829 * Detaches pending connection <p>, decreases the pending count, and frees
1830 * the pending connection. The connection might have been queued to a specific
1831 * server as well as to the proxy. The session also gets marked unqueued.
willy tarreau18a957c2006-04-12 19:26:23 +02001832 */
willy tarreaudfece232006-05-02 00:19:57 +02001833static void pendconn_free(struct pendconn *p) {
1834 LIST_DEL(&p->list);
1835 p->sess->pend_pos = NULL;
1836 if (p->srv)
1837 p->srv->nbpend--;
1838 else
1839 p->sess->proxy->nbpend--;
willy tarreauf32f5242006-05-02 22:54:52 +02001840 p->sess->proxy->totpend--;
willy tarreaudfece232006-05-02 00:19:57 +02001841 pool_free(pendconn, p);
1842}
1843
1844/* Returns the first pending connection for server <s>, which may be NULL if
1845 * nothing is pending.
1846 */
1847static inline struct pendconn *pendconn_from_srv(struct server *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001848 if (!s->nbpend)
1849 return NULL;
1850
1851 return LIST_ELEM(s->pendconns.n, struct pendconn *, list);
1852}
1853
willy tarreaudfece232006-05-02 00:19:57 +02001854/* Returns the first pending connection for proxy <px>, which may be NULL if
1855 * nothing is pending.
willy tarreau18a957c2006-04-12 19:26:23 +02001856 */
willy tarreaudfece232006-05-02 00:19:57 +02001857static inline struct pendconn *pendconn_from_px(struct proxy *px) {
1858 if (!px->nbpend)
1859 return NULL;
1860
1861 return LIST_ELEM(px->pendconns.n, struct pendconn *, list);
willy tarreau18a957c2006-04-12 19:26:23 +02001862}
1863
willy tarreaubc2eda62006-05-04 15:16:23 +02001864/* Detaches the next pending connection from either a server or a proxy, and
1865 * returns its associated session. If no pending connection is found, NULL is
1866 * returned. Note that neither <srv> nor <px> can be NULL.
willy tarreau18a957c2006-04-12 19:26:23 +02001867 */
willy tarreaubc2eda62006-05-04 15:16:23 +02001868static struct session *pendconn_get_next_sess(struct server *srv, struct proxy *px) {
willy tarreau18a957c2006-04-12 19:26:23 +02001869 struct pendconn *p;
1870 struct session *sess;
1871
willy tarreaubc2eda62006-05-04 15:16:23 +02001872 p = pendconn_from_srv(srv);
willy tarreaudfece232006-05-02 00:19:57 +02001873 if (!p) {
willy tarreaubc2eda62006-05-04 15:16:23 +02001874 p = pendconn_from_px(px);
willy tarreaudfece232006-05-02 00:19:57 +02001875 if (!p)
1876 return NULL;
willy tarreaubc2eda62006-05-04 15:16:23 +02001877 p->sess->srv = srv;
willy tarreaudfece232006-05-02 00:19:57 +02001878 }
willy tarreau18a957c2006-04-12 19:26:23 +02001879 sess = p->sess;
1880 pendconn_free(p);
1881 return sess;
1882}
1883
willy tarreaudfece232006-05-02 00:19:57 +02001884/* Adds the session <sess> to the pending connection list of server <sess>->srv
1885 * or to the one of <sess>->proxy if srv is NULL. All counters and back pointers
1886 * are updated accordingly. Returns NULL if no memory is available, otherwise the
1887 * pendconn itself.
willy tarreau18a957c2006-04-12 19:26:23 +02001888 */
willy tarreaudfece232006-05-02 00:19:57 +02001889static struct pendconn *pendconn_add(struct session *sess) {
willy tarreau18a957c2006-04-12 19:26:23 +02001890 struct pendconn *p;
1891
1892 p = pool_alloc(pendconn);
1893 if (!p)
1894 return NULL;
1895
willy tarreau18a957c2006-04-12 19:26:23 +02001896 sess->pend_pos = p;
willy tarreaudfece232006-05-02 00:19:57 +02001897 p->sess = sess;
1898 p->srv = sess->srv;
1899 if (sess->srv) {
1900 LIST_ADDQ(&sess->srv->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001901 sess->logs.srv_queue_size += sess->srv->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001902 sess->srv->nbpend++;
1903 } else {
1904 LIST_ADDQ(&sess->proxy->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001905 sess->logs.prx_queue_size += sess->proxy->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001906 sess->proxy->nbpend++;
1907 }
willy tarreauf32f5242006-05-02 22:54:52 +02001908 sess->proxy->totpend++;
willy tarreau18a957c2006-04-12 19:26:23 +02001909 return p;
1910}
1911
willy tarreau59a6cc22006-05-12 01:29:08 +02001912/* returns 0 if nothing has to be done for server <s> regarding queued connections,
1913 * and non-zero otherwise. Suited for and if/else usage.
1914 */
1915static inline int may_dequeue_tasks(struct server *s, struct proxy *p) {
1916 return (s && (s->nbpend || p->nbpend) &&
1917 s->maxconn && s->cur_sess < s->maxconn && s->queue_mgt);
1918}
1919
1920
1921
willy tarreau18a957c2006-04-12 19:26:23 +02001922/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +01001923/* more specific functions ***************************************/
1924/*********************************************************************/
1925
1926/* some prototypes */
1927static int maintain_proxies(void);
1928
willy tarreaub952e1d2005-12-18 01:31:20 +01001929/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001930 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1931 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001932static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001933#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001934 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1935#else
willy tarreaua1598082005-12-17 13:08:06 +01001936#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001937 return getsockname(fd, (struct sockaddr *)sa, salen);
1938#else
1939 return -1;
1940#endif
1941#endif
1942}
1943
1944/*
1945 * frees the context associated to a session. It must have been removed first.
1946 */
willy tarreaudfece232006-05-02 00:19:57 +02001947static void session_free(struct session *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001948 if (s->pend_pos)
1949 pendconn_free(s->pend_pos);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001950 if (s->req)
1951 pool_free(buffer, s->req);
1952 if (s->rep)
1953 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001954
1955 if (s->rsp_cap != NULL) {
1956 struct cap_hdr *h;
1957 for (h = s->proxy->rsp_cap; h; h = h->next) {
1958 if (s->rsp_cap[h->index] != NULL)
1959 pool_free_to(h->pool, s->rsp_cap[h->index]);
1960 }
1961 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1962 }
1963 if (s->req_cap != NULL) {
1964 struct cap_hdr *h;
1965 for (h = s->proxy->req_cap; h; h = h->next) {
1966 if (s->req_cap[h->index] != NULL)
1967 pool_free_to(h->pool, s->req_cap[h->index]);
1968 }
1969 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1970 }
1971
willy tarreaua1598082005-12-17 13:08:06 +01001972 if (s->logs.uri)
1973 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001974 if (s->logs.cli_cookie)
1975 pool_free(capture, s->logs.cli_cookie);
1976 if (s->logs.srv_cookie)
1977 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001978
willy tarreau5cbea6f2005-12-17 12:48:26 +01001979 pool_free(session, s);
1980}
1981
willy tarreau0f7af912005-12-17 12:21:26 +01001982
1983/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01001984 * This function recounts the number of usable active and backup servers for
1985 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001986 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01001987 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001988static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001989 struct server *srv;
1990
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001991 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001992 for (srv = px->srv; srv != NULL; srv = srv->next) {
1993 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001994 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001995 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001996 px->tot_wbck += srv->eweight + 1;
1997 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001998 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001999 px->tot_wact += srv->eweight + 1;
2000 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01002001 }
2002 }
2003}
2004
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002005/* This function recomputes the server map for proxy px. It
2006 * relies on px->tot_wact and px->tot_wbck, so it must be
2007 * called after recount_servers(). It also expects px->srv_map
2008 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01002009 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002010static void recalc_server_map(struct proxy *px) {
2011 int o, tot, flag;
2012 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01002013
willy tarreau4c8c2b52006-03-24 19:36:41 +01002014 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002015 flag = SRV_RUNNING;
2016 tot = px->tot_wact;
2017 } else if (px->srv_bck) {
2018 flag = SRV_RUNNING | SRV_BACKUP;
2019 if (px->options & PR_O_USE_ALL_BK)
2020 tot = px->tot_wbck;
2021 else
2022 tot = 1; /* the first server is enough */
2023 } else {
2024 px->srv_map_sz = 0;
2025 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002026 }
Willy TARREAU3481c462006-03-01 22:37:57 +01002027
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002028 /* this algorithm gives priority to the first server, which means that
2029 * it will respect the declaration order for equivalent weights, and
2030 * that whatever the weights, the first server called will always be
2031 * the first declard. This is an important asumption for the backup
2032 * case, where we want the first server only.
2033 */
2034 for (cur = px->srv; cur; cur = cur->next)
2035 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002036
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002037 for (o = 0; o < tot; o++) {
2038 int max = 0;
2039 best = NULL;
2040 for (cur = px->srv; cur; cur = cur->next) {
2041 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
2042 int v;
2043
2044 /* If we are forced to return only one server, we don't want to
2045 * go further, because we would return the wrong one due to
2046 * divide overflow.
2047 */
2048 if (tot == 1) {
2049 best = cur;
2050 break;
2051 }
2052
2053 cur->wscore += cur->eweight + 1;
2054 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
2055 if (best == NULL || v > max) {
2056 max = v;
2057 best = cur;
2058 }
2059 }
2060 }
2061 px->srv_map[o] = best;
2062 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002063 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002064 px->srv_map_sz = tot;
2065}
Willy TARREAU3481c462006-03-01 22:37:57 +01002066
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002067/*
willy tarreau898db9d2006-04-12 20:29:08 +02002068 * This function tries to find a running server with free connection slots for
2069 * the proxy <px> following the round-robin method.
2070 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2071 * to point to the next server. If no valid server is found, NULL is returned.
2072 */
2073static inline struct server *get_server_rr_with_conns(struct proxy *px) {
2074 int newidx;
2075 struct server *srv;
2076
2077 if (px->srv_map_sz == 0)
2078 return NULL;
2079
2080 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2081 px->srv_rr_idx = 0;
2082 newidx = px->srv_rr_idx;
2083
2084 do {
2085 srv = px->srv_map[newidx++];
2086 if (!srv->maxconn || srv->cur_sess < srv->maxconn) {
2087 px->srv_rr_idx = newidx;
2088 return srv;
2089 }
2090 if (newidx == px->srv_map_sz)
2091 newidx = 0;
2092 } while (newidx != px->srv_rr_idx);
2093
2094 return NULL;
2095}
2096
2097
2098/*
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002099 * This function tries to find a running server for the proxy <px> following
willy tarreau898db9d2006-04-12 20:29:08 +02002100 * the round-robin method.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002101 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2102 * to point to the next server. If no valid server is found, NULL is returned.
2103 */
2104static inline struct server *get_server_rr(struct proxy *px) {
2105 if (px->srv_map_sz == 0)
2106 return NULL;
2107
2108 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2109 px->srv_rr_idx = 0;
2110 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01002111}
2112
willy tarreau62084d42006-03-24 18:57:41 +01002113
2114/*
willy tarreau1a3442d2006-03-24 21:03:20 +01002115 * This function tries to find a running server for the proxy <px> following
2116 * the source hash method. Depending on the number of active/backup servers,
2117 * it will either look for active servers, or for backup servers.
2118 * If any server is found, it will be returned. If no valid server is found,
2119 * NULL is returned.
2120 */
2121static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002122 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01002123
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002124 if (px->srv_map_sz == 0)
2125 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01002126
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002127 l = h = 0;
willy tarreaucd655352006-04-29 12:11:46 +02002128 if (px->srv_act > 1 || (px->srv_act == 0 && px->srv_bck > 1)) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002129 while ((l + sizeof (int)) <= len) {
2130 h ^= ntohl(*(unsigned int *)(&addr[l]));
2131 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01002132 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002133 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01002134 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002135 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01002136}
2137
2138
2139/*
willy tarreaudfece232006-05-02 00:19:57 +02002140 * This function marks the session as 'assigned' in direct or dispatch modes,
2141 * or tries to assign one in balance mode, according to the algorithm. It does
2142 * nothing if the session had already been assigned a server.
2143 *
2144 * It may return :
willy tarreau000375f2006-05-09 23:15:58 +02002145 * SRV_STATUS_OK if everything is OK. s->srv will be valid.
2146 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
2147 * SRV_STATUS_FULL if all servers are saturated. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002148 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2149 *
2150 * Upon successful return, the session flag SN_ASSIGNED to indicate that it does
2151 * not need to be called anymore. This usually means that s->srv can be trusted
2152 * in balance and direct modes. This flag is not cleared, so it's to the caller
2153 * to clear it if required (eg: redispatch).
2154 *
willy tarreau0f7af912005-12-17 12:21:26 +01002155 */
willy tarreau0f7af912005-12-17 12:21:26 +01002156
willy tarreaudfece232006-05-02 00:19:57 +02002157int assign_server(struct session *s) {
willy tarreau12350152005-12-18 01:03:27 +01002158#ifdef DEBUG_FULL
willy tarreaudfece232006-05-02 00:19:57 +02002159 fprintf(stderr,"assign_server : s=%p\n",s);
willy tarreau12350152005-12-18 01:03:27 +01002160#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002161
willy tarreaudfece232006-05-02 00:19:57 +02002162 if (s->pend_pos)
2163 return SRV_STATUS_INTERNAL;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002164
willy tarreaudfece232006-05-02 00:19:57 +02002165 if (!(s->flags & SN_ASSIGNED)) {
2166 if ((s->proxy->options & PR_O_BALANCE) && !(s->flags & SN_DIRECT)) {
2167 if (!s->proxy->srv_act && !s->proxy->srv_bck)
2168 return SRV_STATUS_NOSRV;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002169
willy tarreaudfece232006-05-02 00:19:57 +02002170 if (s->proxy->options & PR_O_BALANCE_RR) {
2171 s->srv = get_server_rr_with_conns(s->proxy);
2172 if (!s->srv)
2173 return SRV_STATUS_FULL;
2174 }
2175 else if (s->proxy->options & PR_O_BALANCE_SH) {
2176 int len;
2177
2178 if (s->cli_addr.ss_family == AF_INET)
2179 len = 4;
2180 else if (s->cli_addr.ss_family == AF_INET6)
2181 len = 16;
2182 else /* unknown IP family */
2183 return SRV_STATUS_INTERNAL;
2184
2185 s->srv = get_server_sh(s->proxy,
2186 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2187 len);
2188 }
2189 else /* unknown balancing algorithm */
2190 return SRV_STATUS_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002191 }
willy tarreaudfece232006-05-02 00:19:57 +02002192 s->flags |= SN_ASSIGNED;
2193 }
2194 return SRV_STATUS_OK;
2195}
willy tarreau1a3442d2006-03-24 21:03:20 +01002196
willy tarreaudfece232006-05-02 00:19:57 +02002197/*
2198 * This function assigns a server address to a session, and sets SN_ADDR_SET.
2199 * The address is taken from the currently assigned server, or from the
2200 * dispatch or transparent address.
2201 *
2202 * It may return :
2203 * SRV_STATUS_OK if everything is OK.
2204 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2205 *
2206 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
2207 * not cleared, so it's to the caller to clear it if required.
2208 *
2209 */
2210int assign_server_address(struct session *s) {
2211#ifdef DEBUG_FULL
2212 fprintf(stderr,"assign_server_address : s=%p\n",s);
2213#endif
2214
2215 if (s->flags & SN_DIRECT || s->proxy->options & PR_O_BALANCE) {
2216 /* A server is necessarily known for this session */
2217 if (!(s->flags & SN_ASSIGNED))
2218 return SRV_STATUS_INTERNAL;
2219
2220 s->srv_addr = s->srv->addr;
willy tarreau1a3442d2006-03-24 21:03:20 +01002221
willy tarreaudfece232006-05-02 00:19:57 +02002222 /* if this server remaps proxied ports, we'll use
2223 * the port the client connected to with an offset. */
2224 if (s->srv->state & SRV_MAPPORTS) {
2225 struct sockaddr_in sockname;
2226 socklen_t namelen = sizeof(sockname);
2227
2228 if (!(s->proxy->options & PR_O_TRANSP) ||
2229 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2230 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2231 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
willy tarreau1a3442d2006-03-24 21:03:20 +01002232 }
willy tarreau0f7af912005-12-17 12:21:26 +01002233 }
willy tarreaua1598082005-12-17 13:08:06 +01002234 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002235 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002236 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002237 }
2238 else if (s->proxy->options & PR_O_TRANSP) {
2239 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002240 socklen_t salen = sizeof(s->srv_addr);
2241
willy tarreau5cbea6f2005-12-17 12:48:26 +01002242 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2243 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaudfece232006-05-02 00:19:57 +02002244 return SRV_STATUS_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002245 }
2246 }
willy tarreau0f7af912005-12-17 12:21:26 +01002247
willy tarreaudfece232006-05-02 00:19:57 +02002248 s->flags |= SN_ADDR_SET;
2249 return SRV_STATUS_OK;
2250}
willy tarreaua41a8b42005-12-17 14:02:24 +01002251
willy tarreaudfece232006-05-02 00:19:57 +02002252/* This function assigns a server to session <s> if required, and can add the
2253 * connection to either the assigned server's queue or to the proxy's queue.
2254 *
2255 * Returns :
2256 *
2257 * SRV_STATUS_OK if everything is OK.
willy tarreau000375f2006-05-09 23:15:58 +02002258 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002259 * SRV_STATUS_QUEUED if the connection has been queued.
2260 * SRV_STATUS_FULL if the server(s) is/are saturated and the
2261 * connection could not be queued.
2262 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2263 *
2264 */
2265int assign_server_and_queue(struct session *s) {
2266 struct pendconn *p;
2267 int err;
2268
2269 if (s->pend_pos)
2270 return SRV_STATUS_INTERNAL;
2271
2272 if (s->flags & SN_ASSIGNED) {
2273 /* a server does not need to be assigned, perhaps because we're in
2274 * direct mode, or in dispatch or transparent modes where the server
2275 * is not needed.
2276 */
2277 if (s->srv &&
2278 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2279 p = pendconn_add(s);
2280 if (p)
2281 return SRV_STATUS_QUEUED;
2282 else
2283 return SRV_STATUS_FULL;
2284 }
2285 return SRV_STATUS_OK;
2286 }
2287
2288 /* a server needs to be assigned */
2289 err = assign_server(s);
2290 switch (err) {
2291 case SRV_STATUS_OK:
2292 /* in balance mode, we might have servers with connection limits */
2293 if (s->srv != NULL &&
2294 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2295 p = pendconn_add(s);
2296 if (p)
2297 return SRV_STATUS_QUEUED;
2298 else
2299 return SRV_STATUS_FULL;
2300 }
2301 return SRV_STATUS_OK;
2302
2303 case SRV_STATUS_FULL:
2304 /* queue this session into the proxy's queue */
2305 p = pendconn_add(s);
2306 if (p)
2307 return SRV_STATUS_QUEUED;
2308 else
2309 return SRV_STATUS_FULL;
2310
2311 case SRV_STATUS_NOSRV:
2312 case SRV_STATUS_INTERNAL:
2313 return err;
2314 default:
2315 return SRV_STATUS_INTERNAL;
willy tarreaua41a8b42005-12-17 14:02:24 +01002316 }
willy tarreaudfece232006-05-02 00:19:57 +02002317}
2318
2319
2320/*
2321 * This function initiates a connection to the server assigned to this session
2322 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
2323 * It can return one of :
2324 * - SN_ERR_NONE if everything's OK
2325 * - SN_ERR_SRVTO if there are no more servers
2326 * - SN_ERR_SRVCL if the connection was refused by the server
2327 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
2328 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
2329 * - SN_ERR_INTERNAL for any other purely internal errors
2330 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
2331 */
2332int connect_server(struct session *s) {
2333 int fd, err;
2334
2335 if (!(s->flags & SN_ADDR_SET)) {
2336 err = assign_server_address(s);
2337 if (err != SRV_STATUS_OK)
2338 return SN_ERR_INTERNAL;
2339 }
willy tarreaua41a8b42005-12-17 14:02:24 +01002340
willy tarreau0f7af912005-12-17 12:21:26 +01002341 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002342 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002343
2344 if (errno == ENFILE)
2345 send_log(s->proxy, LOG_EMERG,
2346 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2347 s->proxy->id, maxfd);
2348 else if (errno == EMFILE)
2349 send_log(s->proxy, LOG_EMERG,
2350 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2351 s->proxy->id, maxfd);
2352 else if (errno == ENOBUFS || errno == ENOMEM)
2353 send_log(s->proxy, LOG_EMERG,
2354 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2355 s->proxy->id, maxfd);
2356 /* this is a resource error */
2357 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002358 }
2359
willy tarreau9fe663a2005-12-17 13:02:59 +01002360 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002361 /* do not log anything there, it's a normal condition when this option
2362 * is used to serialize connections to a server !
2363 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002364 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2365 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002366 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002367 }
2368
willy tarreau0f7af912005-12-17 12:21:26 +01002369 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2370 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002371 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002372 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002373 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002374 }
2375
willy tarreaub952e1d2005-12-18 01:31:20 +01002376 if (s->proxy->options & PR_O_TCP_SRV_KA)
2377 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2378
willy tarreau0174f312005-12-18 01:02:42 +01002379 /* allow specific binding :
2380 * - server-specific at first
2381 * - proxy-specific next
2382 */
2383 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2384 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2385 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2386 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2387 s->proxy->id, s->srv->id);
2388 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002389 send_log(s->proxy, LOG_EMERG,
2390 "Cannot bind to source address before connect() for server %s/%s.\n",
2391 s->proxy->id, s->srv->id);
2392 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002393 }
2394 }
2395 else if (s->proxy->options & PR_O_BIND_SRC) {
2396 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2397 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2398 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2399 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002400 send_log(s->proxy, LOG_EMERG,
2401 "Cannot bind to source address before connect() for server %s/%s.\n",
2402 s->proxy->id, s->srv->id);
2403 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002404 }
willy tarreaua1598082005-12-17 13:08:06 +01002405 }
2406
willy tarreaub1285d52005-12-18 01:20:14 +01002407 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2408 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2409
2410 if (errno == EAGAIN || errno == EADDRINUSE) {
2411 char *msg;
2412 if (errno == EAGAIN) /* no free ports left, try again later */
2413 msg = "no free ports";
2414 else
2415 msg = "local address already in use";
2416
2417 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002418 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002419 send_log(s->proxy, LOG_EMERG,
2420 "Connect() failed for server %s/%s: %s.\n",
2421 s->proxy->id, s->srv->id, msg);
2422 return SN_ERR_RESOURCE;
2423 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002424 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002425 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002426 return SN_ERR_SRVTO;
2427 } else {
2428 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002429 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002430 close(fd);
2431 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002432 }
2433 }
2434
willy tarreau5cbea6f2005-12-17 12:48:26 +01002435 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002436 fdtab[fd].read = &event_srv_read;
2437 fdtab[fd].write = &event_srv_write;
2438 fdtab[fd].state = FD_STCONN; /* connection in progress */
2439
2440 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002441#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2442 if (PrevReadEvent) {
2443 assert(!(FD_ISSET(fd, PrevReadEvent)));
2444 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2445 }
2446#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002447
2448 fd_insert(fd);
willy tarreau926a3572006-05-01 15:26:35 +02002449 if (s->srv)
2450 s->srv->cur_sess++;
willy tarreau0f7af912005-12-17 12:21:26 +01002451
2452 if (s->proxy->contimeout)
2453 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2454 else
2455 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002456 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002457}
2458
2459/*
2460 * this function is called on a read event from a client socket.
2461 * It returns 0.
2462 */
2463int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002464 struct task *t = fdtab[fd].owner;
2465 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002466 struct buffer *b = s->req;
2467 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002468
willy tarreau12350152005-12-18 01:03:27 +01002469#ifdef DEBUG_FULL
2470 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2471#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002472
willy tarreau0f7af912005-12-17 12:21:26 +01002473 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002474#ifdef FILL_BUFFERS
2475 while (1)
2476#else
2477 do
2478#endif
2479 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002480 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2481 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002482 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002483 }
2484 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002485 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002486 }
2487 else {
2488 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002489 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2490 * since it means that the rewrite protection has been removed. This
2491 * implies that the if statement can be removed.
2492 */
2493 if (max > b->rlim - b->data)
2494 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002495 }
2496
2497 if (max == 0) { /* not anymore room to store data */
2498 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002499 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002500 }
2501
willy tarreau3242e862005-12-17 12:27:53 +01002502#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002503 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002504 int skerr;
2505 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002506
willy tarreau5cbea6f2005-12-17 12:48:26 +01002507 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2508 if (skerr)
2509 ret = -1;
2510 else
2511 ret = recv(fd, b->r, max, 0);
2512 }
willy tarreau3242e862005-12-17 12:27:53 +01002513#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002514 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002515#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002516 if (ret > 0) {
2517 b->r += ret;
2518 b->l += ret;
2519 s->res_cr = RES_DATA;
2520
2521 if (b->r == b->data + BUFSIZE) {
2522 b->r = b->data; /* wrap around the buffer */
2523 }
willy tarreaua1598082005-12-17 13:08:06 +01002524
2525 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002526 /* we hope to read more data or to get a close on next round */
2527 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002528 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002529 else if (ret == 0) {
2530 s->res_cr = RES_NULL;
2531 break;
2532 }
2533 else if (errno == EAGAIN) {/* ignore EAGAIN */
2534 break;
2535 }
2536 else {
2537 s->res_cr = RES_ERROR;
2538 fdtab[fd].state = FD_STERROR;
2539 break;
2540 }
2541 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002542#ifndef FILL_BUFFERS
2543 while (0);
2544#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002545 }
2546 else {
2547 s->res_cr = RES_ERROR;
2548 fdtab[fd].state = FD_STERROR;
2549 }
2550
willy tarreau5cbea6f2005-12-17 12:48:26 +01002551 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002552 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002553 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2554 else
2555 tv_eternity(&s->crexpire);
2556
2557 task_wakeup(&rq, t);
2558 }
willy tarreau0f7af912005-12-17 12:21:26 +01002559
willy tarreau0f7af912005-12-17 12:21:26 +01002560 return 0;
2561}
2562
2563
2564/*
2565 * this function is called on a read event from a server socket.
2566 * It returns 0.
2567 */
2568int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002569 struct task *t = fdtab[fd].owner;
2570 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002571 struct buffer *b = s->rep;
2572 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002573
willy tarreau12350152005-12-18 01:03:27 +01002574#ifdef DEBUG_FULL
2575 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2576#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002577
willy tarreau0f7af912005-12-17 12:21:26 +01002578 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002579#ifdef FILL_BUFFERS
2580 while (1)
2581#else
2582 do
2583#endif
2584 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002585 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2586 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002587 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002588 }
2589 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002590 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002591 }
2592 else {
2593 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002594 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2595 * since it means that the rewrite protection has been removed. This
2596 * implies that the if statement can be removed.
2597 */
2598 if (max > b->rlim - b->data)
2599 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002600 }
2601
2602 if (max == 0) { /* not anymore room to store data */
2603 FD_CLR(fd, StaticReadEvent);
2604 break;
2605 }
2606
willy tarreau3242e862005-12-17 12:27:53 +01002607#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002608 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002609 int skerr;
2610 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002611
willy tarreau5cbea6f2005-12-17 12:48:26 +01002612 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2613 if (skerr)
2614 ret = -1;
2615 else
2616 ret = recv(fd, b->r, max, 0);
2617 }
willy tarreau3242e862005-12-17 12:27:53 +01002618#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002619 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002620#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002621 if (ret > 0) {
2622 b->r += ret;
2623 b->l += ret;
2624 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002625
willy tarreau5cbea6f2005-12-17 12:48:26 +01002626 if (b->r == b->data + BUFSIZE) {
2627 b->r = b->data; /* wrap around the buffer */
2628 }
willy tarreaua1598082005-12-17 13:08:06 +01002629
2630 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002631 /* we hope to read more data or to get a close on next round */
2632 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002633 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002634 else if (ret == 0) {
2635 s->res_sr = RES_NULL;
2636 break;
2637 }
2638 else if (errno == EAGAIN) {/* ignore EAGAIN */
2639 break;
2640 }
2641 else {
2642 s->res_sr = RES_ERROR;
2643 fdtab[fd].state = FD_STERROR;
2644 break;
2645 }
2646 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002647#ifndef FILL_BUFFERS
2648 while (0);
2649#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002650 }
2651 else {
2652 s->res_sr = RES_ERROR;
2653 fdtab[fd].state = FD_STERROR;
2654 }
2655
willy tarreau5cbea6f2005-12-17 12:48:26 +01002656 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002657 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002658 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2659 else
2660 tv_eternity(&s->srexpire);
2661
2662 task_wakeup(&rq, t);
2663 }
willy tarreau0f7af912005-12-17 12:21:26 +01002664
willy tarreau0f7af912005-12-17 12:21:26 +01002665 return 0;
2666}
2667
2668/*
2669 * this function is called on a write event from a client socket.
2670 * It returns 0.
2671 */
2672int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002673 struct task *t = fdtab[fd].owner;
2674 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002675 struct buffer *b = s->rep;
2676 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002677
willy tarreau12350152005-12-18 01:03:27 +01002678#ifdef DEBUG_FULL
2679 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2680#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002681
2682 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002683 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002684 // max = BUFSIZE; BUG !!!!
2685 max = 0;
2686 }
2687 else if (b->r > b->w) {
2688 max = b->r - b->w;
2689 }
2690 else
2691 max = b->data + BUFSIZE - b->w;
2692
willy tarreau0f7af912005-12-17 12:21:26 +01002693 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002694 if (max == 0) {
2695 s->res_cw = RES_NULL;
2696 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002697 tv_eternity(&s->cwexpire);
2698 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002699 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002700 }
2701
willy tarreau3242e862005-12-17 12:27:53 +01002702#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002703 {
2704 int skerr;
2705 socklen_t lskerr = sizeof(skerr);
2706
2707 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2708 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002709 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002710 else
willy tarreau3242e862005-12-17 12:27:53 +01002711 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002712 }
willy tarreau3242e862005-12-17 12:27:53 +01002713#else
willy tarreau0f7af912005-12-17 12:21:26 +01002714 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002715#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002716
2717 if (ret > 0) {
2718 b->l -= ret;
2719 b->w += ret;
2720
2721 s->res_cw = RES_DATA;
2722
2723 if (b->w == b->data + BUFSIZE) {
2724 b->w = b->data; /* wrap around the buffer */
2725 }
2726 }
2727 else if (ret == 0) {
2728 /* nothing written, just make as if we were never called */
2729// s->res_cw = RES_NULL;
2730 return 0;
2731 }
2732 else if (errno == EAGAIN) /* ignore EAGAIN */
2733 return 0;
2734 else {
2735 s->res_cw = RES_ERROR;
2736 fdtab[fd].state = FD_STERROR;
2737 }
2738 }
2739 else {
2740 s->res_cw = RES_ERROR;
2741 fdtab[fd].state = FD_STERROR;
2742 }
2743
willy tarreaub1ff9db2005-12-17 13:51:03 +01002744 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002745 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002746 /* FIXME: to prevent the client from expiring read timeouts during writes,
2747 * we refresh it. A solution would be to merge read+write timeouts into a
2748 * unique one, although that needs some study particularly on full-duplex
2749 * TCP connections. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002750 s->crexpire = s->cwexpire;
2751 }
willy tarreau0f7af912005-12-17 12:21:26 +01002752 else
2753 tv_eternity(&s->cwexpire);
2754
willy tarreau5cbea6f2005-12-17 12:48:26 +01002755 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002756 return 0;
2757}
2758
2759
2760/*
2761 * this function is called on a write event from a server socket.
2762 * It returns 0.
2763 */
2764int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002765 struct task *t = fdtab[fd].owner;
2766 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002767 struct buffer *b = s->req;
2768 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002769
willy tarreau12350152005-12-18 01:03:27 +01002770#ifdef DEBUG_FULL
2771 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2772#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002773
2774 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002775 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002776 // max = BUFSIZE; BUG !!!!
2777 max = 0;
2778 }
2779 else if (b->r > b->w) {
2780 max = b->r - b->w;
2781 }
2782 else
2783 max = b->data + BUFSIZE - b->w;
2784
willy tarreau0f7af912005-12-17 12:21:26 +01002785 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002786 if (max == 0) {
2787 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002788 if (s->srv_state == SV_STCONN) {
2789 int skerr;
2790 socklen_t lskerr = sizeof(skerr);
2791 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2792 if (skerr) {
2793 s->res_sw = RES_ERROR;
2794 fdtab[fd].state = FD_STERROR;
2795 task_wakeup(&rq, t);
2796 tv_eternity(&s->swexpire);
2797 FD_CLR(fd, StaticWriteEvent);
2798 return 0;
2799 }
2800 }
2801
willy tarreau0f7af912005-12-17 12:21:26 +01002802 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002803 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002804 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002805 tv_eternity(&s->swexpire);
2806 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002807 return 0;
2808 }
2809
willy tarreau3242e862005-12-17 12:27:53 +01002810#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002811 {
2812 int skerr;
2813 socklen_t lskerr = sizeof(skerr);
2814 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2815 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002816 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002817 else
willy tarreau3242e862005-12-17 12:27:53 +01002818 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002819 }
willy tarreau3242e862005-12-17 12:27:53 +01002820#else
willy tarreau0f7af912005-12-17 12:21:26 +01002821 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002822#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002823 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002824 if (ret > 0) {
2825 b->l -= ret;
2826 b->w += ret;
2827
2828 s->res_sw = RES_DATA;
2829
2830 if (b->w == b->data + BUFSIZE) {
2831 b->w = b->data; /* wrap around the buffer */
2832 }
2833 }
2834 else if (ret == 0) {
2835 /* nothing written, just make as if we were never called */
2836 // s->res_sw = RES_NULL;
2837 return 0;
2838 }
2839 else if (errno == EAGAIN) /* ignore EAGAIN */
2840 return 0;
2841 else {
2842 s->res_sw = RES_ERROR;
2843 fdtab[fd].state = FD_STERROR;
2844 }
2845 }
2846 else {
2847 s->res_sw = RES_ERROR;
2848 fdtab[fd].state = FD_STERROR;
2849 }
2850
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002851 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2852 * otherwise it could loop indefinitely !
2853 */
2854 if (s->srv_state != SV_STCONN) {
2855 if (s->proxy->srvtimeout) {
2856 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002857 /* FIXME: to prevent the server from expiring read timeouts during writes,
2858 * we refresh it. A solution would be to merge read+write+connect timeouts
2859 * into a unique one since we don't mind expiring on read or write, and none
2860 * of them is enabled while waiting for connect(), although that needs some
2861 * study particularly on full-duplex TCP connections. */
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002862 s->srexpire = s->swexpire;
2863 }
2864 else
2865 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002866 }
willy tarreau0f7af912005-12-17 12:21:26 +01002867
willy tarreau5cbea6f2005-12-17 12:48:26 +01002868 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002869 return 0;
2870}
2871
2872
2873/*
willy tarreaue39cd132005-12-17 13:00:18 +01002874 * returns a message to the client ; the connection is shut down for read,
2875 * and the request is cleared so that no server connection can be initiated.
2876 * The client must be in a valid state for this (HEADER, DATA ...).
2877 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002878 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002879 */
2880void client_retnclose(struct session *s, int len, const char *msg) {
2881 FD_CLR(s->cli_fd, StaticReadEvent);
2882 FD_SET(s->cli_fd, StaticWriteEvent);
2883 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002884 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002885 shutdown(s->cli_fd, SHUT_RD);
2886 s->cli_state = CL_STSHUTR;
2887 strcpy(s->rep->data, msg);
2888 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002889 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002890 s->rep->r += len;
2891 s->req->l = 0;
2892}
2893
2894
2895/*
2896 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002897 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002898 */
2899void client_return(struct session *s, int len, const char *msg) {
2900 strcpy(s->rep->data, msg);
2901 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002902 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002903 s->rep->r += len;
2904 s->req->l = 0;
2905}
2906
willy tarreau9fe663a2005-12-17 13:02:59 +01002907/*
2908 * send a log for the session when we have enough info about it
2909 */
2910void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002911 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002912 struct proxy *p = s->proxy;
2913 int log;
2914 char *uri;
2915 char *pxid;
2916 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002917 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002918
2919 /* This is a first attempt at a better logging system.
2920 * For now, we rely on send_log() to provide the date, although it obviously
2921 * is the date of the log and not of the request, and most fields are not
2922 * computed.
2923 */
2924
willy tarreaua1598082005-12-17 13:08:06 +01002925 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002926
willy tarreau8a86dbf2005-12-18 00:45:59 +01002927 if (s->cli_addr.ss_family == AF_INET)
2928 inet_ntop(AF_INET,
2929 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2930 pn, sizeof(pn));
2931 else
2932 inet_ntop(AF_INET6,
2933 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2934 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002935
willy tarreauc1cae632005-12-17 14:12:23 +01002936 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002937 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002938 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002939
willy tarreauc1cae632005-12-17 14:12:23 +01002940 tm = localtime(&s->logs.tv_accept.tv_sec);
2941 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002942 char tmpline[MAX_SYSLOG_LEN], *h;
2943 int hdr;
2944
2945 h = tmpline;
2946 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2947 *(h++) = ' ';
2948 *(h++) = '{';
2949 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2950 if (hdr)
2951 *(h++) = '|';
2952 if (s->req_cap[hdr] != NULL)
2953 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2954 }
2955 *(h++) = '}';
2956 }
2957
2958 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2959 *(h++) = ' ';
2960 *(h++) = '{';
2961 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2962 if (hdr)
2963 *(h++) = '|';
2964 if (s->rsp_cap[hdr] != NULL)
2965 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2966 }
2967 *(h++) = '}';
2968 }
2969
2970 if (h < tmpline + sizeof(tmpline) - 4) {
2971 *(h++) = ' ';
2972 *(h++) = '"';
2973 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2974 *(h++) = '"';
2975 }
2976 *h = '\0';
2977
willy tarreau5e69b162006-05-12 19:49:37 +02002978 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%d/%s%d %d %s%lld %s %s %c%c%c%c %d/%d/%d %d/%d%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002979 pn,
2980 (s->cli_addr.ss_family == AF_INET) ?
2981 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2982 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002983 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2984 tm->tm_hour, tm->tm_min, tm->tm_sec,
2985 pxid, srv,
2986 s->logs.t_request,
willy tarreauf32f5242006-05-02 22:54:52 +02002987 (s->logs.t_queue >= 0) ? s->logs.t_queue - s->logs.t_request : -1,
2988 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreaua1598082005-12-17 13:08:06 +01002989 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002990 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2991 s->logs.status,
2992 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002993 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2994 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002995 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2996 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2997 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2998 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau5e69b162006-05-12 19:49:37 +02002999 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3000 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01003001 }
3002 else {
willy tarreau5e69b162006-05-12 19:49:37 +02003003 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 %d/%d\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01003004 pn,
3005 (s->cli_addr.ss_family == AF_INET) ?
3006 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3007 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01003008 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3009 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01003010 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01003011 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003012 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3013 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01003014 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01003015 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreau5e69b162006-05-12 19:49:37 +02003016 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3017 s->logs.srv_queue_size, s->logs.prx_queue_size);
willy tarreaua1598082005-12-17 13:08:06 +01003018 }
3019
3020 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003021}
3022
willy tarreaue39cd132005-12-17 13:00:18 +01003023
3024/*
willy tarreau0f7af912005-12-17 12:21:26 +01003025 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01003026 * to an accept. It tries to accept as many connections as possible.
3027 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01003028 */
3029int event_accept(int fd) {
3030 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003031 struct session *s;
3032 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01003033 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01003034 int max_accept;
3035
3036 if (global.nbproc > 1)
3037 max_accept = 8; /* let other processes catch some connections too */
3038 else
3039 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003040
willy tarreauc2becdc2006-03-19 19:36:48 +01003041 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003042 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003043 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01003044
willy tarreaub1285d52005-12-18 01:20:14 +01003045 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
3046 switch (errno) {
3047 case EAGAIN:
3048 case EINTR:
3049 case ECONNABORTED:
3050 return 0; /* nothing more to accept */
3051 case ENFILE:
3052 send_log(p, LOG_EMERG,
3053 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
3054 p->id, maxfd);
3055 return 0;
3056 case EMFILE:
3057 send_log(p, LOG_EMERG,
3058 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
3059 p->id, maxfd);
3060 return 0;
3061 case ENOBUFS:
3062 case ENOMEM:
3063 send_log(p, LOG_EMERG,
3064 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
3065 p->id, maxfd);
3066 return 0;
3067 default:
3068 return 0;
3069 }
3070 }
willy tarreau0f7af912005-12-17 12:21:26 +01003071
willy tarreau5cbea6f2005-12-17 12:48:26 +01003072 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
3073 Alert("out of memory in event_accept().\n");
3074 FD_CLR(fd, StaticReadEvent);
3075 p->state = PR_STIDLE;
3076 close(cfd);
3077 return 0;
3078 }
willy tarreau0f7af912005-12-17 12:21:26 +01003079
willy tarreaub1285d52005-12-18 01:20:14 +01003080 /* if this session comes from a known monitoring system, we want to ignore
3081 * it as soon as possible, which means closing it immediately for TCP.
3082 */
3083 s->flags = 0;
3084 if (addr.ss_family == AF_INET &&
3085 p->mon_mask.s_addr &&
3086 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
3087 if (p->mode == PR_MODE_TCP) {
3088 close(cfd);
3089 pool_free(session, s);
3090 continue;
3091 }
3092 s->flags |= SN_MONITOR;
3093 }
3094
willy tarreau5cbea6f2005-12-17 12:48:26 +01003095 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3096 Alert("out of memory in event_accept().\n");
3097 FD_CLR(fd, StaticReadEvent);
3098 p->state = PR_STIDLE;
3099 close(cfd);
3100 pool_free(session, s);
3101 return 0;
3102 }
willy tarreau0f7af912005-12-17 12:21:26 +01003103
willy tarreau5cbea6f2005-12-17 12:48:26 +01003104 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01003105 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003106 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
3107 close(cfd);
3108 pool_free(task, t);
3109 pool_free(session, s);
3110 return 0;
3111 }
willy tarreau0f7af912005-12-17 12:21:26 +01003112
willy tarreau5cbea6f2005-12-17 12:48:26 +01003113 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
3114 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
3115 (char *) &one, sizeof(one)) == -1)) {
3116 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
3117 close(cfd);
3118 pool_free(task, t);
3119 pool_free(session, s);
3120 return 0;
3121 }
willy tarreau0f7af912005-12-17 12:21:26 +01003122
willy tarreaub952e1d2005-12-18 01:31:20 +01003123 if (p->options & PR_O_TCP_CLI_KA)
3124 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
3125
willy tarreau9fe663a2005-12-17 13:02:59 +01003126 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02003127 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
willy tarreau9fe663a2005-12-17 13:02:59 +01003128 t->state = TASK_IDLE;
3129 t->process = process_session;
3130 t->context = s;
3131
3132 s->task = t;
3133 s->proxy = p;
3134 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
3135 s->srv_state = SV_STIDLE;
3136 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01003137
willy tarreau9fe663a2005-12-17 13:02:59 +01003138 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
3139 s->cli_fd = cfd;
3140 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003141 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01003142 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01003143
willy tarreaub1285d52005-12-18 01:20:14 +01003144 if (s->flags & SN_MONITOR)
3145 s->logs.logwait = 0;
3146 else
3147 s->logs.logwait = p->to_log;
3148
willy tarreaua1598082005-12-17 13:08:06 +01003149 s->logs.tv_accept = now;
3150 s->logs.t_request = -1;
willy tarreauf32f5242006-05-02 22:54:52 +02003151 s->logs.t_queue = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003152 s->logs.t_connect = -1;
3153 s->logs.t_data = -1;
3154 s->logs.t_close = 0;
3155 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01003156 s->logs.cli_cookie = NULL;
3157 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01003158 s->logs.status = -1;
3159 s->logs.bytes = 0;
willy tarreau5e69b162006-05-12 19:49:37 +02003160 s->logs.prx_queue_size = 0; /* we get the number of pending conns before us */
3161 s->logs.srv_queue_size = 0; /* we will get this number soon */
willy tarreau9fe663a2005-12-17 13:02:59 +01003162
willy tarreau2f6ba652005-12-17 13:57:42 +01003163 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02003164 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01003165
willy tarreau4302f492005-12-18 01:00:37 +01003166 if (p->nb_req_cap > 0) {
3167 if ((s->req_cap =
3168 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
3169 == NULL) { /* no memory */
3170 close(cfd); /* nothing can be done for this fd without memory */
3171 pool_free(task, t);
3172 pool_free(session, s);
3173 return 0;
3174 }
3175 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
3176 }
3177 else
3178 s->req_cap = NULL;
3179
3180 if (p->nb_rsp_cap > 0) {
3181 if ((s->rsp_cap =
3182 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
3183 == NULL) { /* no memory */
3184 if (s->req_cap != NULL)
3185 pool_free_to(p->req_cap_pool, s->req_cap);
3186 close(cfd); /* nothing can be done for this fd without memory */
3187 pool_free(task, t);
3188 pool_free(session, s);
3189 return 0;
3190 }
3191 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
3192 }
3193 else
3194 s->rsp_cap = NULL;
3195
willy tarreau5cbea6f2005-12-17 12:48:26 +01003196 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
3197 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003198 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003199 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01003200
willy tarreau8a86dbf2005-12-18 00:45:59 +01003201 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003202 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003203 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003204 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01003205
willy tarreau9fe663a2005-12-17 13:02:59 +01003206 if (p->to_log) {
3207 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01003208 if (s->logs.logwait & LW_CLIP)
3209 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01003210 sess_log(s);
3211 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01003212 else if (s->cli_addr.ss_family == AF_INET) {
3213 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
3214 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
3215 sn, sizeof(sn)) &&
3216 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3217 pn, sizeof(pn))) {
3218 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3219 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
3220 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
3221 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3222 }
3223 }
3224 else {
3225 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
3226 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
3227 sn, sizeof(sn)) &&
3228 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
3229 pn, sizeof(pn))) {
3230 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3231 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
3232 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
3233 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3234 }
3235 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003236 }
willy tarreau0f7af912005-12-17 12:21:26 +01003237
willy tarreau982249e2005-12-18 00:57:06 +01003238 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01003239 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003240 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01003241 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01003242 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003243 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003244 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01003245 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01003246
willy tarreau8a86dbf2005-12-18 00:45:59 +01003247 if (s->cli_addr.ss_family == AF_INET) {
3248 char pn[INET_ADDRSTRLEN];
3249 inet_ntop(AF_INET,
3250 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3251 pn, sizeof(pn));
3252
3253 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3254 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3255 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
3256 }
3257 else {
3258 char pn[INET6_ADDRSTRLEN];
3259 inet_ntop(AF_INET6,
3260 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3261 pn, sizeof(pn));
3262
3263 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3264 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3265 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3266 }
3267
willy tarreauef900ab2005-12-17 12:52:52 +01003268 write(1, trash, len);
3269 }
willy tarreau0f7af912005-12-17 12:21:26 +01003270
willy tarreau5cbea6f2005-12-17 12:48:26 +01003271 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003272 if (s->rsp_cap != NULL)
3273 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3274 if (s->req_cap != NULL)
3275 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003276 close(cfd); /* nothing can be done for this fd without memory */
3277 pool_free(task, t);
3278 pool_free(session, s);
3279 return 0;
3280 }
willy tarreau4302f492005-12-18 01:00:37 +01003281
willy tarreau5cbea6f2005-12-17 12:48:26 +01003282 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003283 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003284 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3285 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003286 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003287 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003288
willy tarreau5cbea6f2005-12-17 12:48:26 +01003289 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3290 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003291 if (s->rsp_cap != NULL)
3292 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3293 if (s->req_cap != NULL)
3294 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003295 close(cfd); /* nothing can be done for this fd without memory */
3296 pool_free(task, t);
3297 pool_free(session, s);
3298 return 0;
3299 }
3300 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003301 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003302 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 +01003303
willy tarreau5cbea6f2005-12-17 12:48:26 +01003304 fdtab[cfd].read = &event_cli_read;
3305 fdtab[cfd].write = &event_cli_write;
3306 fdtab[cfd].owner = t;
3307 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003308
willy tarreaub1285d52005-12-18 01:20:14 +01003309 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3310 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3311 /* Either we got a request from a monitoring system on an HTTP instance,
3312 * or we're in health check mode with the 'httpchk' option enabled. In
3313 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3314 */
3315 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3316 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3317 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003318 }
3319 else {
3320 FD_SET(cfd, StaticReadEvent);
3321 }
3322
willy tarreaub952e1d2005-12-18 01:31:20 +01003323#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3324 if (PrevReadEvent) {
3325 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3326 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3327 }
3328#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003329 fd_insert(cfd);
3330
3331 tv_eternity(&s->cnexpire);
3332 tv_eternity(&s->srexpire);
3333 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003334 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003335 tv_eternity(&s->cwexpire);
3336
willy tarreaub1285d52005-12-18 01:20:14 +01003337 if (s->proxy->clitimeout) {
3338 if (FD_ISSET(cfd, StaticReadEvent))
3339 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3340 if (FD_ISSET(cfd, StaticWriteEvent))
3341 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3342 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003343
willy tarreaub1285d52005-12-18 01:20:14 +01003344 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003345
3346 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003347
3348 if (p->mode != PR_MODE_HEALTH)
3349 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003350
3351 p->nbconn++;
3352 actconn++;
3353 totalconn++;
3354
willy tarreaub952e1d2005-12-18 01:31:20 +01003355 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003356 } /* end of while (p->nbconn < p->maxconn) */
3357 return 0;
3358}
willy tarreau0f7af912005-12-17 12:21:26 +01003359
willy tarreau0f7af912005-12-17 12:21:26 +01003360
willy tarreau5cbea6f2005-12-17 12:48:26 +01003361/*
3362 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003363 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3364 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003365 * or -1 if an error occured.
3366 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003367int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003368 struct task *t = fdtab[fd].owner;
3369 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003370 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003371 socklen_t lskerr = sizeof(skerr);
3372
willy tarreau05be12b2006-03-19 19:35:00 +01003373 skerr = 1;
3374 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3375 || (skerr != 0)) {
3376 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003377 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003378 fdtab[fd].state = FD_STERROR;
3379 FD_CLR(fd, StaticWriteEvent);
3380 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003381 else if (s->result != -1) {
3382 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003383 if (s->proxy->options & PR_O_HTTP_CHK) {
3384 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003385 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003386 * so we'll send the request, and won't wake the checker up now.
3387 */
3388#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003389 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003390#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003391 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003392#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003393 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003394 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3395 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3396 return 0;
3397 }
willy tarreau05be12b2006-03-19 19:35:00 +01003398 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003399 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003400 FD_CLR(fd, StaticWriteEvent);
3401 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003402 }
3403 else {
3404 /* good TCP connection is enough */
3405 s->result = 1;
3406 }
3407 }
3408
3409 task_wakeup(&rq, t);
3410 return 0;
3411}
3412
willy tarreau0f7af912005-12-17 12:21:26 +01003413
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003414/*
3415 * This function is used only for server health-checks. It handles
3416 * the server's reply to an HTTP request. It returns 1 if the server replies
3417 * 2xx or 3xx (valid responses), or -1 in other cases.
3418 */
3419int event_srv_chk_r(int fd) {
3420 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003421 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003422 struct task *t = fdtab[fd].owner;
3423 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003424 int skerr;
3425 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003426
willy tarreaua4a583a2005-12-18 01:39:19 +01003427 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003428
willy tarreau05be12b2006-03-19 19:35:00 +01003429 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3430 if (!skerr) {
3431#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003432 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003433#else
willy tarreau05be12b2006-03-19 19:35:00 +01003434 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3435 * but the connection was closed on the remote end. Fortunately, recv still
3436 * works correctly and we don't need to do the getsockopt() on linux.
3437 */
3438 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003439#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003440
3441 if ((len >= sizeof("HTTP/1.0 000")) &&
3442 !memcmp(reply, "HTTP/1.", 7) &&
3443 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3444 result = 1;
3445 }
3446
3447 if (result == -1)
3448 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003449
3450 if (s->result != -1)
3451 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003452
3453 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003454 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003455 return 0;
3456}
3457
3458
3459/*
3460 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3461 * and moves <end> just after the end of <str>.
3462 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3463 * the shift value (positive or negative) is returned.
3464 * If there's no space left, the move is not done.
3465 *
3466 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003467int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003468 int delta;
3469 int len;
3470
3471 len = strlen(str);
3472 delta = len - (end - pos);
3473
3474 if (delta + b->r >= b->data + BUFSIZE)
3475 return 0; /* no space left */
3476
3477 /* first, protect the end of the buffer */
3478 memmove(end + delta, end, b->data + b->l - end);
3479
3480 /* now, copy str over pos */
3481 memcpy(pos, str,len);
3482
willy tarreau5cbea6f2005-12-17 12:48:26 +01003483 /* we only move data after the displaced zone */
3484 if (b->r > pos) b->r += delta;
3485 if (b->w > pos) b->w += delta;
3486 if (b->h > pos) b->h += delta;
3487 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003488 b->l += delta;
3489
3490 return delta;
3491}
3492
willy tarreau8337c6b2005-12-17 13:41:01 +01003493/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003494 * len is 0.
3495 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003496int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003497 int delta;
3498
3499 delta = len - (end - pos);
3500
3501 if (delta + b->r >= b->data + BUFSIZE)
3502 return 0; /* no space left */
3503
Willy TARREAUe78ae262006-01-08 01:24:12 +01003504 if (b->data + b->l < end)
3505 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3506 return 0;
3507
willy tarreau0f7af912005-12-17 12:21:26 +01003508 /* first, protect the end of the buffer */
3509 memmove(end + delta, end, b->data + b->l - end);
3510
3511 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003512 if (len)
3513 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003514
willy tarreau5cbea6f2005-12-17 12:48:26 +01003515 /* we only move data after the displaced zone */
3516 if (b->r > pos) b->r += delta;
3517 if (b->w > pos) b->w += delta;
3518 if (b->h > pos) b->h += delta;
3519 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003520 b->l += delta;
3521
3522 return delta;
3523}
3524
3525
3526int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3527 char *old_dst = dst;
3528
3529 while (*str) {
3530 if (*str == '\\') {
3531 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003532 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003533 int len, num;
3534
3535 num = *str - '0';
3536 str++;
3537
willy tarreau8a86dbf2005-12-18 00:45:59 +01003538 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003539 len = matches[num].rm_eo - matches[num].rm_so;
3540 memcpy(dst, src + matches[num].rm_so, len);
3541 dst += len;
3542 }
3543
3544 }
3545 else if (*str == 'x') {
3546 unsigned char hex1, hex2;
3547 str++;
3548
willy tarreauc1f47532005-12-18 01:08:26 +01003549 hex1 = toupper(*str++) - '0';
3550 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003551
3552 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3553 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3554 *dst++ = (hex1<<4) + hex2;
3555 }
3556 else
3557 *dst++ = *str++;
3558 }
3559 else
3560 *dst++ = *str++;
3561 }
3562 *dst = 0;
3563 return dst - old_dst;
3564}
3565
willy tarreauc1f47532005-12-18 01:08:26 +01003566static int ishex(char s)
3567{
3568 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3569}
3570
3571/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3572char *check_replace_string(char *str)
3573{
3574 char *err = NULL;
3575 while (*str) {
3576 if (*str == '\\') {
3577 err = str; /* in case of a backslash, we return the pointer to it */
3578 str++;
3579 if (!*str)
3580 return err;
3581 else if (isdigit((int)*str))
3582 err = NULL;
3583 else if (*str == 'x') {
3584 str++;
3585 if (!ishex(*str))
3586 return err;
3587 str++;
3588 if (!ishex(*str))
3589 return err;
3590 err = NULL;
3591 }
3592 else {
3593 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3594 err = NULL;
3595 }
3596 }
3597 str++;
3598 }
3599 return err;
3600}
3601
3602
willy tarreau9fe663a2005-12-17 13:02:59 +01003603
willy tarreau0f7af912005-12-17 12:21:26 +01003604/*
3605 * manages the client FSM and its socket. BTW, it also tries to handle the
3606 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3607 * 0 else.
3608 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003609int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003610 int s = t->srv_state;
3611 int c = t->cli_state;
3612 struct buffer *req = t->req;
3613 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003614 int method_checked = 0;
3615 appsess *asession_temp = NULL;
3616 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003617
willy tarreau750a4722005-12-17 13:21:24 +01003618#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003619 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3620 cli_stnames[c], srv_stnames[s],
3621 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3622 t->crexpire.tv_sec, t->crexpire.tv_usec,
3623 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003624#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003625 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3626 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3627 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3628 //);
3629 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003630 /* now parse the partial (or complete) headers */
3631 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3632 char *ptr;
3633 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003634 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003635
willy tarreau5cbea6f2005-12-17 12:48:26 +01003636 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003637
willy tarreau0f7af912005-12-17 12:21:26 +01003638 /* look for the end of the current header */
3639 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3640 ptr++;
3641
willy tarreau5cbea6f2005-12-17 12:48:26 +01003642 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003643 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02003644
3645 /*
3646 * first, let's check that it's not a leading empty line, in
3647 * which case we'll ignore and remove it (according to RFC2616).
3648 */
3649 if (req->h == req->data) {
3650 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3651 if (ptr > req->r - 2) {
3652 /* this is a partial header, let's wait for more to come */
3653 req->lr = ptr;
3654 break;
3655 }
3656
3657 /* now we know that *ptr is either \r or \n,
3658 * and that there are at least 1 char after it.
3659 */
3660 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3661 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3662 else
3663 req->lr = ptr + 2; /* \r\n or \n\r */
3664 /* ignore empty leading lines */
3665 buffer_replace2(req, req->h, req->lr, NULL, 0);
3666 req->h = req->lr;
3667 continue;
3668 }
3669
willy tarreau5cbea6f2005-12-17 12:48:26 +01003670 /* we can only get here after an end of headers */
3671 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003672
willy tarreaue39cd132005-12-17 13:00:18 +01003673 if (t->flags & SN_CLDENY) {
3674 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003675 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003676 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003677 if (!(t->flags & SN_ERR_MASK))
3678 t->flags |= SN_ERR_PRXCOND;
3679 if (!(t->flags & SN_FINST_MASK))
3680 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003681 return 1;
3682 }
3683
willy tarreau5cbea6f2005-12-17 12:48:26 +01003684 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003685 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3686 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003687 }
willy tarreau0f7af912005-12-17 12:21:26 +01003688
willy tarreau9fe663a2005-12-17 13:02:59 +01003689 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003690 if (t->cli_addr.ss_family == AF_INET) {
3691 unsigned char *pn;
3692 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3693 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3694 pn[0], pn[1], pn[2], pn[3]);
3695 buffer_replace2(req, req->h, req->h, trash, len);
3696 }
3697 else if (t->cli_addr.ss_family == AF_INET6) {
3698 char pn[INET6_ADDRSTRLEN];
3699 inet_ntop(AF_INET6,
3700 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3701 pn, sizeof(pn));
3702 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3703 buffer_replace2(req, req->h, req->h, trash, len);
3704 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003705 }
3706
willy tarreau25c4ea52005-12-18 00:49:49 +01003707 /* add a "connection: close" line if needed */
3708 if (t->proxy->options & PR_O_HTTP_CLOSE)
3709 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3710
willy tarreau982249e2005-12-18 00:57:06 +01003711 if (!memcmp(req->data, "POST ", 5)) {
3712 /* this is a POST request, which is not cacheable by default */
3713 t->flags |= SN_POST;
3714 }
willy tarreaucd878942005-12-17 13:27:43 +01003715
willy tarreau5cbea6f2005-12-17 12:48:26 +01003716 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003717 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003718
willy tarreau750a4722005-12-17 13:21:24 +01003719 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003720 /* FIXME: we'll set the client in a wait state while we try to
3721 * connect to the server. Is this really needed ? wouldn't it be
willy tarreau0889c962006-04-24 14:36:48 +02003722 * better to release the maximum of system buffers instead ?
3723 * The solution is to enable the FD but set its time-out to
3724 * eternity as long as the server-side does not enable data xfer.
3725 * CL_STDATA also has to take care of this, which is done below.
3726 */
willy tarreauef900ab2005-12-17 12:52:52 +01003727 //FD_CLR(t->cli_fd, StaticReadEvent);
3728 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003729
3730 /* FIXME: if we break here (as up to 1.1.23), having the client
3731 * shutdown its connection can lead to an abort further.
3732 * it's better to either return 1 or even jump directly to the
3733 * data state which will save one schedule.
3734 */
3735 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003736
3737 if (!t->proxy->clitimeout ||
3738 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3739 /* If the client has no timeout, or if the server is not ready yet,
3740 * and we know for sure that it can expire, then it's cleaner to
3741 * disable the timeout on the client side so that too low values
3742 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003743 *
3744 * FIXME-20050705: the server needs a way to re-enable this time-out
3745 * when it switches its state, otherwise a client can stay connected
3746 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003747 */
3748 tv_eternity(&t->crexpire);
3749
willy tarreau197e8ec2005-12-17 14:10:59 +01003750 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003751 }
willy tarreau0f7af912005-12-17 12:21:26 +01003752
Willy TARREAU13032e72006-03-12 17:31:45 +01003753 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3754 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003755 /* this is a partial header, let's wait for more to come */
3756 req->lr = ptr;
3757 break;
3758 }
willy tarreau0f7af912005-12-17 12:21:26 +01003759
willy tarreau5cbea6f2005-12-17 12:48:26 +01003760 /* now we know that *ptr is either \r or \n,
3761 * and that there are at least 1 char after it.
3762 */
3763 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3764 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3765 else
3766 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003767
willy tarreau5cbea6f2005-12-17 12:48:26 +01003768 /*
3769 * now we know that we have a full header ; we can do whatever
3770 * we want with these pointers :
3771 * req->h = beginning of header
3772 * ptr = end of header (first \r or \n)
3773 * req->lr = beginning of next line (next rep->h)
3774 * req->r = end of data (not used at this stage)
3775 */
willy tarreau0f7af912005-12-17 12:21:26 +01003776
willy tarreau12350152005-12-18 01:03:27 +01003777 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3778 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3779 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3780
3781 /* skip ; */
3782 request_line++;
3783
3784 /* look if we have a jsessionid */
3785
3786 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3787
3788 /* skip jsessionid= */
3789 request_line += t->proxy->appsession_name_len + 1;
3790
3791 /* First try if we allready have an appsession */
3792 asession_temp = &local_asession;
3793
3794 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3795 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3796 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3797 return 0;
3798 }
3799
3800 /* Copy the sessionid */
3801 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3802 asession_temp->sessid[t->proxy->appsession_len] = 0;
3803 asession_temp->serverid = NULL;
3804
3805 /* only do insert, if lookup fails */
3806 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3807 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3808 Alert("Not enough memory process_cli():asession:calloc().\n");
3809 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3810 return 0;
3811 }
3812 asession_temp->sessid = local_asession.sessid;
3813 asession_temp->serverid = local_asession.serverid;
3814 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003815 } /* end if (chtbl_lookup()) */
3816 else {
willy tarreau12350152005-12-18 01:03:27 +01003817 /*free wasted memory;*/
3818 pool_free_to(apools.sessid, local_asession.sessid);
3819 }
3820
3821 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3822 asession_temp->request_count++;
3823
3824#if defined(DEBUG_HASH)
3825 print_table(&(t->proxy->htbl_proxy));
3826#endif
3827
3828 if (asession_temp->serverid == NULL) {
3829 Alert("Found Application Session without matching server.\n");
3830 } else {
3831 struct server *srv = t->proxy->srv;
3832 while (srv) {
3833 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3834 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3835 /* we found the server and it's usable */
3836 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02003837 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01003838 t->srv = srv;
3839 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003840 } else {
willy tarreau12350152005-12-18 01:03:27 +01003841 t->flags &= ~SN_CK_MASK;
3842 t->flags |= SN_CK_DOWN;
3843 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003844 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003845 srv = srv->next;
3846 }/* end while(srv) */
3847 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003848 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003849 else {
3850 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3851 }
willy tarreau598da412005-12-18 01:07:29 +01003852 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003853 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003854 else{
3855 //printf("No Methode-Header with Session-String\n");
3856 }
3857
willy tarreau8337c6b2005-12-17 13:41:01 +01003858 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003859 /* we have a complete HTTP request that we must log */
3860 int urilen;
3861
willy tarreaua1598082005-12-17 13:08:06 +01003862 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003863 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003864 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003865 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003866 if (!(t->flags & SN_ERR_MASK))
3867 t->flags |= SN_ERR_PRXCOND;
3868 if (!(t->flags & SN_FINST_MASK))
3869 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003870 return 1;
3871 }
3872
3873 urilen = ptr - req->h;
3874 if (urilen >= REQURI_LEN)
3875 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003876 memcpy(t->logs.uri, req->h, urilen);
3877 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003878
willy tarreaua1598082005-12-17 13:08:06 +01003879 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003880 sess_log(t);
3881 }
willy tarreau4302f492005-12-18 01:00:37 +01003882 else if (t->logs.logwait & LW_REQHDR) {
3883 struct cap_hdr *h;
3884 int len;
3885 for (h = t->proxy->req_cap; h; h = h->next) {
3886 if ((h->namelen + 2 <= ptr - req->h) &&
3887 (req->h[h->namelen] == ':') &&
3888 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3889
3890 if (t->req_cap[h->index] == NULL)
3891 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3892
3893 len = ptr - (req->h + h->namelen + 2);
3894 if (len > h->len)
3895 len = h->len;
3896
3897 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3898 t->req_cap[h->index][len]=0;
3899 }
3900 }
3901
3902 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003903
willy tarreau5cbea6f2005-12-17 12:48:26 +01003904 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003905
willy tarreau982249e2005-12-18 00:57:06 +01003906 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003907 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003908 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 +01003909 max = ptr - req->h;
3910 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003911 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003912 trash[len++] = '\n';
3913 write(1, trash, len);
3914 }
willy tarreau0f7af912005-12-17 12:21:26 +01003915
willy tarreau25c4ea52005-12-18 00:49:49 +01003916
3917 /* remove "connection: " if needed */
3918 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3919 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3920 delete_header = 1;
3921 }
3922
willy tarreau5cbea6f2005-12-17 12:48:26 +01003923 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003924 if (!delete_header && t->proxy->req_exp != NULL
3925 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003926 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003927 char term;
3928
3929 term = *ptr;
3930 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003931 exp = t->proxy->req_exp;
3932 do {
3933 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3934 switch (exp->action) {
3935 case ACT_ALLOW:
3936 if (!(t->flags & SN_CLDENY))
3937 t->flags |= SN_CLALLOW;
3938 break;
3939 case ACT_REPLACE:
3940 if (!(t->flags & SN_CLDENY)) {
3941 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3942 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3943 }
3944 break;
3945 case ACT_REMOVE:
3946 if (!(t->flags & SN_CLDENY))
3947 delete_header = 1;
3948 break;
3949 case ACT_DENY:
3950 if (!(t->flags & SN_CLALLOW))
3951 t->flags |= SN_CLDENY;
3952 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003953 case ACT_PASS: /* we simply don't deny this one */
3954 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003955 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003956 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003957 }
willy tarreaue39cd132005-12-17 13:00:18 +01003958 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003959 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003960 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003961
willy tarreau240afa62005-12-17 13:14:35 +01003962 /* Now look for cookies. Conforming to RFC2109, we have to support
3963 * attributes whose name begin with a '$', and associate them with
3964 * the right cookie, if we want to delete this cookie.
3965 * So there are 3 cases for each cookie read :
3966 * 1) it's a special attribute, beginning with a '$' : ignore it.
3967 * 2) it's a server id cookie that we *MAY* want to delete : save
3968 * some pointers on it (last semi-colon, beginning of cookie...)
3969 * 3) it's an application cookie : we *MAY* have to delete a previous
3970 * "special" cookie.
3971 * At the end of loop, if a "special" cookie remains, we may have to
3972 * remove it. If no application cookie persists in the header, we
3973 * *MUST* delete it
3974 */
willy tarreau12350152005-12-18 01:03:27 +01003975 if (!delete_header &&
3976 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003977 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003978 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003979 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003980 char *del_colon, *del_cookie, *colon;
3981 int app_cookies;
3982
willy tarreau5cbea6f2005-12-17 12:48:26 +01003983 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003984 colon = p1;
3985 /* del_cookie == NULL => nothing to be deleted */
3986 del_colon = del_cookie = NULL;
3987 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003988
3989 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003990 /* skip spaces and colons, but keep an eye on these ones */
3991 while (p1 < ptr) {
3992 if (*p1 == ';' || *p1 == ',')
3993 colon = p1;
3994 else if (!isspace((int)*p1))
3995 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003996 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003997 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003998
3999 if (p1 == ptr)
4000 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004001
4002 /* p1 is at the beginning of the cookie name */
4003 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01004004 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004005 p2++;
4006
4007 if (p2 == ptr)
4008 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004009
4010 p3 = p2 + 1; /* skips the '=' sign */
4011 if (p3 == ptr)
4012 break;
4013
willy tarreau240afa62005-12-17 13:14:35 +01004014 p4 = p3;
4015 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004016 p4++;
4017
4018 /* here, we have the cookie name between p1 and p2,
4019 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01004020 * we can process it :
4021 *
4022 * Cookie: NAME=VALUE;
4023 * | || || |
4024 * | || || +--> p4
4025 * | || |+-------> p3
4026 * | || +--------> p2
4027 * | |+------------> p1
4028 * | +-------------> colon
4029 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01004030 */
4031
willy tarreau240afa62005-12-17 13:14:35 +01004032 if (*p1 == '$') {
4033 /* skip this one */
4034 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004035 else {
4036 /* first, let's see if we want to capture it */
4037 if (t->proxy->capture_name != NULL &&
4038 t->logs.cli_cookie == NULL &&
4039 (p4 - p1 >= t->proxy->capture_namelen) &&
4040 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4041 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004042
willy tarreau8337c6b2005-12-17 13:41:01 +01004043 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4044 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01004045 } else {
4046 if (log_len > t->proxy->capture_len)
4047 log_len = t->proxy->capture_len;
4048 memcpy(t->logs.cli_cookie, p1, log_len);
4049 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01004050 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004051 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004052
4053 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4054 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
4055 /* Cool... it's the right one */
4056 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01004057 char *delim;
4058
4059 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4060 * have the server ID betweek p3 and delim, and the original cookie between
4061 * delim+1 and p4. Otherwise, delim==p4 :
4062 *
4063 * Cookie: NAME=SRV~VALUE;
4064 * | || || | |
4065 * | || || | +--> p4
4066 * | || || +--------> delim
4067 * | || |+-----------> p3
4068 * | || +------------> p2
4069 * | |+----------------> p1
4070 * | +-----------------> colon
4071 * +------------------------> req->h
4072 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004073
willy tarreau0174f312005-12-18 01:02:42 +01004074 if (t->proxy->options & PR_O_COOK_PFX) {
4075 for (delim = p3; delim < p4; delim++)
4076 if (*delim == COOKIE_DELIM)
4077 break;
4078 }
4079 else
4080 delim = p4;
4081
4082
4083 /* Here, we'll look for the first running server which supports the cookie.
4084 * This allows to share a same cookie between several servers, for example
4085 * to dedicate backup servers to specific servers only.
willy tarreau422bb2e2006-05-10 04:27:21 +02004086 * However, to prevent clients from sticking to cookie-less backup server
4087 * when they have incidentely learned an empty cookie, we simply ignore
4088 * empty cookies and mark them as invalid.
willy tarreau0174f312005-12-18 01:02:42 +01004089 */
willy tarreau422bb2e2006-05-10 04:27:21 +02004090 if (delim == p3)
4091 srv = NULL;
4092
willy tarreau0174f312005-12-18 01:02:42 +01004093 while (srv) {
4094 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
4095 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4096 /* we found the server and it's usable */
4097 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004098 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau0174f312005-12-18 01:02:42 +01004099 t->srv = srv;
4100 break;
willy tarreau12350152005-12-18 01:03:27 +01004101 } else {
willy tarreau0174f312005-12-18 01:02:42 +01004102 /* we found a server, but it's down */
4103 t->flags &= ~SN_CK_MASK;
4104 t->flags |= SN_CK_DOWN;
4105 }
4106 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004107 srv = srv->next;
4108 }
4109
willy tarreau0174f312005-12-18 01:02:42 +01004110 if (!srv && !(t->flags & SN_CK_DOWN)) {
4111 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01004112 t->flags &= ~SN_CK_MASK;
4113 t->flags |= SN_CK_INVALID;
4114 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004115
willy tarreau0174f312005-12-18 01:02:42 +01004116 /* depending on the cookie mode, we may have to either :
4117 * - delete the complete cookie if we're in insert+indirect mode, so that
4118 * the server never sees it ;
4119 * - remove the server id from the cookie value, and tag the cookie as an
4120 * application cookie so that it does not get accidentely removed later,
4121 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01004122 */
willy tarreau0174f312005-12-18 01:02:42 +01004123 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
4124 buffer_replace2(req, p3, delim + 1, NULL, 0);
4125 p4 -= (delim + 1 - p3);
4126 ptr -= (delim + 1 - p3);
4127 del_cookie = del_colon = NULL;
4128 app_cookies++; /* protect the header from deletion */
4129 }
4130 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01004131 (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 +01004132 del_cookie = p1;
4133 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01004134 }
willy tarreau12350152005-12-18 01:03:27 +01004135 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01004136 /* now we know that we must keep this cookie since it's
4137 * not ours. But if we wanted to delete our cookie
4138 * earlier, we cannot remove the complete header, but we
4139 * can remove the previous block itself.
4140 */
4141 app_cookies++;
4142
4143 if (del_cookie != NULL) {
4144 buffer_replace2(req, del_cookie, p1, NULL, 0);
4145 p4 -= (p1 - del_cookie);
4146 ptr -= (p1 - del_cookie);
4147 del_cookie = del_colon = NULL;
4148 }
willy tarreau240afa62005-12-17 13:14:35 +01004149 }
willy tarreau12350152005-12-18 01:03:27 +01004150
4151 if ((t->proxy->appsession_name != NULL) &&
4152 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4153 /* first, let's see if the cookie is our appcookie*/
4154
4155 /* Cool... it's the right one */
4156
4157 asession_temp = &local_asession;
4158
4159 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4160 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4161 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4162 return 0;
4163 }
4164
4165 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4166 asession_temp->sessid[t->proxy->appsession_len] = 0;
4167 asession_temp->serverid = NULL;
4168
4169 /* only do insert, if lookup fails */
4170 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4171 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4172 Alert("Not enough memory process_cli():asession:calloc().\n");
4173 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4174 return 0;
4175 }
4176
4177 asession_temp->sessid = local_asession.sessid;
4178 asession_temp->serverid = local_asession.serverid;
4179 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4180 }
4181 else{
4182 /* free wasted memory */
4183 pool_free_to(apools.sessid, local_asession.sessid);
4184 }
4185
4186 if (asession_temp->serverid == NULL) {
4187 Alert("Found Application Session without matching server.\n");
4188 } else {
4189 struct server *srv = t->proxy->srv;
4190 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01004191 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01004192 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4193 /* we found the server and it's usable */
4194 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004195 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004196 t->srv = srv;
4197 break;
4198 } else {
4199 t->flags &= ~SN_CK_MASK;
4200 t->flags |= SN_CK_DOWN;
4201 }
4202 }
4203 srv = srv->next;
4204 }/* end while(srv) */
4205 }/* end else if server == NULL */
4206
4207 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01004208 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004209 }
willy tarreau240afa62005-12-17 13:14:35 +01004210
willy tarreau5cbea6f2005-12-17 12:48:26 +01004211 /* we'll have to look for another cookie ... */
4212 p1 = p4;
4213 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01004214
4215 /* There's no more cookie on this line.
4216 * We may have marked the last one(s) for deletion.
4217 * We must do this now in two ways :
4218 * - if there is no app cookie, we simply delete the header ;
4219 * - if there are app cookies, we must delete the end of the
4220 * string properly, including the colon/semi-colon before
4221 * the cookie name.
4222 */
4223 if (del_cookie != NULL) {
4224 if (app_cookies) {
4225 buffer_replace2(req, del_colon, ptr, NULL, 0);
4226 /* WARNING! <ptr> becomes invalid for now. If some code
4227 * below needs to rely on it before the end of the global
4228 * header loop, we need to correct it with this code :
4229 * ptr = del_colon;
4230 */
4231 }
4232 else
4233 delete_header = 1;
4234 }
4235 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004236
4237 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004238 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01004239 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01004240 }
willy tarreau240afa62005-12-17 13:14:35 +01004241 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
4242
willy tarreau5cbea6f2005-12-17 12:48:26 +01004243 req->h = req->lr;
4244 } /* while (req->lr < req->r) */
4245
4246 /* end of header processing (even if incomplete) */
4247
willy tarreauef900ab2005-12-17 12:52:52 +01004248 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4249 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4250 * full. We cannot loop here since event_cli_read will disable it only if
4251 * req->l == rlim-data
4252 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004253 FD_SET(t->cli_fd, StaticReadEvent);
4254 if (t->proxy->clitimeout)
4255 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4256 else
4257 tv_eternity(&t->crexpire);
4258 }
4259
willy tarreaue39cd132005-12-17 13:00:18 +01004260 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01004261 * won't be able to free more later, so the session will never terminate.
4262 */
willy tarreaue39cd132005-12-17 13:00:18 +01004263 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01004264 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01004265 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01004266 if (!(t->flags & SN_ERR_MASK))
4267 t->flags |= SN_ERR_PRXCOND;
4268 if (!(t->flags & SN_FINST_MASK))
4269 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004270 return 1;
4271 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004272 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004273 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004274 tv_eternity(&t->crexpire);
4275 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004276 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004277 if (!(t->flags & SN_ERR_MASK))
4278 t->flags |= SN_ERR_CLICL;
4279 if (!(t->flags & SN_FINST_MASK))
4280 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004281 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004282 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004283 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4284
4285 /* read timeout : give up with an error message.
4286 */
4287 t->logs.status = 408;
4288 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004289 if (!(t->flags & SN_ERR_MASK))
4290 t->flags |= SN_ERR_CLITO;
4291 if (!(t->flags & SN_FINST_MASK))
4292 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004293 return 1;
4294 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004295
4296 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004297 }
4298 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004299 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004300 /* FIXME: this error handling is partly buggy because we always report
4301 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4302 * or HEADER phase. BTW, it's not logical to expire the client while
4303 * we're waiting for the server to connect.
4304 */
willy tarreau0f7af912005-12-17 12:21:26 +01004305 /* read or write error */
4306 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004307 tv_eternity(&t->crexpire);
4308 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004309 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004310 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004311 if (!(t->flags & SN_ERR_MASK))
4312 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004313 if (!(t->flags & SN_FINST_MASK)) {
4314 if (t->pend_pos)
4315 t->flags |= SN_FINST_Q;
4316 else if (s == SV_STCONN)
4317 t->flags |= SN_FINST_C;
4318 else
4319 t->flags |= SN_FINST_D;
4320 }
willy tarreau0f7af912005-12-17 12:21:26 +01004321 return 1;
4322 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004323 /* last read, or end of server write */
4324 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004325 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004326 tv_eternity(&t->crexpire);
4327 shutdown(t->cli_fd, SHUT_RD);
4328 t->cli_state = CL_STSHUTR;
4329 return 1;
4330 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004331 /* last server read and buffer empty */
4332 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004333 FD_CLR(t->cli_fd, StaticWriteEvent);
4334 tv_eternity(&t->cwexpire);
4335 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004336 /* We must ensure that the read part is still alive when switching
4337 * to shutw */
4338 FD_SET(t->cli_fd, StaticReadEvent);
4339 if (t->proxy->clitimeout)
4340 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004341 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004342 //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 +01004343 return 1;
4344 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004345 /* read timeout */
4346 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4347 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004348 tv_eternity(&t->crexpire);
4349 shutdown(t->cli_fd, SHUT_RD);
4350 t->cli_state = CL_STSHUTR;
4351 if (!(t->flags & SN_ERR_MASK))
4352 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004353 if (!(t->flags & SN_FINST_MASK)) {
4354 if (t->pend_pos)
4355 t->flags |= SN_FINST_Q;
4356 else if (s == SV_STCONN)
4357 t->flags |= SN_FINST_C;
4358 else
4359 t->flags |= SN_FINST_D;
4360 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004361 return 1;
4362 }
4363 /* write timeout */
4364 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4365 FD_CLR(t->cli_fd, StaticWriteEvent);
4366 tv_eternity(&t->cwexpire);
4367 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004368 /* We must ensure that the read part is still alive when switching
4369 * to shutw */
4370 FD_SET(t->cli_fd, StaticReadEvent);
4371 if (t->proxy->clitimeout)
4372 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4373
willy tarreau036e1ce2005-12-17 13:46:33 +01004374 t->cli_state = CL_STSHUTW;
4375 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004376 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004377 if (!(t->flags & SN_FINST_MASK)) {
4378 if (t->pend_pos)
4379 t->flags |= SN_FINST_Q;
4380 else if (s == SV_STCONN)
4381 t->flags |= SN_FINST_C;
4382 else
4383 t->flags |= SN_FINST_D;
4384 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004385 return 1;
4386 }
willy tarreau0f7af912005-12-17 12:21:26 +01004387
willy tarreauc58fc692005-12-17 14:13:08 +01004388 if (req->l >= req->rlim - req->data) {
4389 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004390 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004391 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004392 FD_CLR(t->cli_fd, StaticReadEvent);
4393 tv_eternity(&t->crexpire);
4394 }
4395 }
4396 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004397 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004398 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4399 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004400 if (!t->proxy->clitimeout ||
4401 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4402 /* If the client has no timeout, or if the server not ready yet, and we
4403 * know for sure that it can expire, then it's cleaner to disable the
4404 * timeout on the client side so that too low values cannot make the
4405 * sessions abort too early.
4406 */
willy tarreau0f7af912005-12-17 12:21:26 +01004407 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004408 else
4409 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004410 }
4411 }
4412
4413 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004414 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004415 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4416 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4417 tv_eternity(&t->cwexpire);
4418 }
4419 }
4420 else { /* buffer not empty */
4421 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4422 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004423 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004424 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004425 /* FIXME: to prevent the client from expiring read timeouts during writes,
4426 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004427 t->crexpire = t->cwexpire;
4428 }
willy tarreau0f7af912005-12-17 12:21:26 +01004429 else
4430 tv_eternity(&t->cwexpire);
4431 }
4432 }
4433 return 0; /* other cases change nothing */
4434 }
4435 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004436 if (t->res_cw == RES_ERROR) {
4437 tv_eternity(&t->cwexpire);
4438 fd_delete(t->cli_fd);
4439 t->cli_state = CL_STCLOSE;
4440 if (!(t->flags & SN_ERR_MASK))
4441 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004442 if (!(t->flags & SN_FINST_MASK)) {
4443 if (t->pend_pos)
4444 t->flags |= SN_FINST_Q;
4445 else if (s == SV_STCONN)
4446 t->flags |= SN_FINST_C;
4447 else
4448 t->flags |= SN_FINST_D;
4449 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004450 return 1;
4451 }
4452 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004453 tv_eternity(&t->cwexpire);
4454 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004455 t->cli_state = CL_STCLOSE;
4456 return 1;
4457 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004458 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4459 tv_eternity(&t->cwexpire);
4460 fd_delete(t->cli_fd);
4461 t->cli_state = CL_STCLOSE;
4462 if (!(t->flags & SN_ERR_MASK))
4463 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004464 if (!(t->flags & SN_FINST_MASK)) {
4465 if (t->pend_pos)
4466 t->flags |= SN_FINST_Q;
4467 else if (s == SV_STCONN)
4468 t->flags |= SN_FINST_C;
4469 else
4470 t->flags |= SN_FINST_D;
4471 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004472 return 1;
4473 }
willy tarreau0f7af912005-12-17 12:21:26 +01004474 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004475 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004476 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4477 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4478 tv_eternity(&t->cwexpire);
4479 }
4480 }
4481 else { /* buffer not empty */
4482 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4483 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004484 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004485 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004486 /* FIXME: to prevent the client from expiring read timeouts during writes,
4487 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004488 t->crexpire = t->cwexpire;
4489 }
willy tarreau0f7af912005-12-17 12:21:26 +01004490 else
4491 tv_eternity(&t->cwexpire);
4492 }
4493 }
4494 return 0;
4495 }
4496 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004497 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004498 tv_eternity(&t->crexpire);
4499 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004500 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004501 if (!(t->flags & SN_ERR_MASK))
4502 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004503 if (!(t->flags & SN_FINST_MASK)) {
4504 if (t->pend_pos)
4505 t->flags |= SN_FINST_Q;
4506 else if (s == SV_STCONN)
4507 t->flags |= SN_FINST_C;
4508 else
4509 t->flags |= SN_FINST_D;
4510 }
willy tarreau0f7af912005-12-17 12:21:26 +01004511 return 1;
4512 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004513 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4514 tv_eternity(&t->crexpire);
4515 fd_delete(t->cli_fd);
4516 t->cli_state = CL_STCLOSE;
4517 return 1;
4518 }
4519 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4520 tv_eternity(&t->crexpire);
4521 fd_delete(t->cli_fd);
4522 t->cli_state = CL_STCLOSE;
4523 if (!(t->flags & SN_ERR_MASK))
4524 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004525 if (!(t->flags & SN_FINST_MASK)) {
4526 if (t->pend_pos)
4527 t->flags |= SN_FINST_Q;
4528 else if (s == SV_STCONN)
4529 t->flags |= SN_FINST_C;
4530 else
4531 t->flags |= SN_FINST_D;
4532 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004533 return 1;
4534 }
willy tarreauef900ab2005-12-17 12:52:52 +01004535 else if (req->l >= req->rlim - req->data) {
4536 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004537
4538 /* FIXME-20050705: is it possible for a client to maintain a session
4539 * after the timeout by sending more data after it receives a close ?
4540 */
4541
willy tarreau0f7af912005-12-17 12:21:26 +01004542 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004543 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004544 FD_CLR(t->cli_fd, StaticReadEvent);
4545 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004546 //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 +01004547 }
4548 }
4549 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004550 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004551 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4552 FD_SET(t->cli_fd, StaticReadEvent);
4553 if (t->proxy->clitimeout)
4554 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4555 else
4556 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004557 //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 +01004558 }
4559 }
4560 return 0;
4561 }
4562 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004563 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004564 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004565 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 +01004566 write(1, trash, len);
4567 }
4568 return 0;
4569 }
4570 return 0;
4571}
4572
willy tarreaudfece232006-05-02 00:19:57 +02004573/* This function turns the server state into the SV_STCLOSE, and sets
4574 * indicators accordingly. Note that if <status> is 0, no message is
4575 * returned.
4576 */
4577void srv_close_with_err(struct session *t, int err, int finst, int status, int msglen, char *msg) {
4578 t->srv_state = SV_STCLOSE;
4579 if (status > 0) {
4580 t->logs.status = status;
4581 if (t->proxy->mode == PR_MODE_HTTP)
4582 client_return(t, msglen, msg);
4583 }
4584 if (!(t->flags & SN_ERR_MASK))
4585 t->flags |= err;
4586 if (!(t->flags & SN_FINST_MASK))
4587 t->flags |= finst;
4588}
4589
4590/*
4591 * This function checks the retry count during the connect() job.
4592 * It updates the session's srv_state and retries, so that the caller knows
4593 * what it has to do. It uses the last connection error to set the log when
4594 * it expires. It returns 1 when it has expired, and 0 otherwise.
4595 */
4596int srv_count_retry_down(struct session *t, int conn_err) {
4597 /* we are in front of a retryable error */
4598 t->conn_retries--;
4599 if (t->conn_retries < 0) {
4600 /* if not retryable anymore, let's abort */
4601 tv_eternity(&t->cnexpire);
4602 srv_close_with_err(t, conn_err, SN_FINST_C,
4603 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4604
4605 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02004606 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02004607 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004608 if (may_dequeue_tasks(t->srv, t->proxy))
4609 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004610 return 1;
4611 }
4612 return 0;
4613}
willy tarreau0f7af912005-12-17 12:21:26 +01004614
4615/*
willy tarreaudfece232006-05-02 00:19:57 +02004616 * This function performs the retryable part of the connect() job.
4617 * It updates the session's srv_state and retries, so that the caller knows
4618 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
4619 * it needs to redispatch.
4620 */
4621int srv_retryable_connect(struct session *t) {
4622 int conn_err;
4623
4624 /* This loop ensures that we stop before the last retry in case of a
4625 * redispatchable server.
4626 */
4627 do {
4628 /* initiate a connection to the server */
4629 conn_err = connect_server(t);
4630 switch (conn_err) {
4631
4632 case SN_ERR_NONE:
4633 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4634 t->srv_state = SV_STCONN;
4635 return 1;
4636
4637 case SN_ERR_INTERNAL:
4638 tv_eternity(&t->cnexpire);
4639 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4640 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4641 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02004642 if (may_dequeue_tasks(t->srv, t->proxy))
4643 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004644 return 1;
4645 }
4646 /* ensure that we have enough retries left */
willy tarreau59a6cc22006-05-12 01:29:08 +02004647 if (srv_count_retry_down(t, conn_err)) {
4648 /* let's try to offer this slot to anybody */
4649 if (may_dequeue_tasks(t->srv, t->proxy))
4650 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004651 return 1;
willy tarreau59a6cc22006-05-12 01:29:08 +02004652 }
willy tarreaudfece232006-05-02 00:19:57 +02004653 } while (t->srv == NULL || t->conn_retries > 0 || !(t->proxy->options & PR_O_REDISP));
4654
4655 /* We're on our last chance, and the REDISP option was specified.
4656 * We will ignore cookie and force to balance or use the dispatcher.
4657 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004658 /* let's try to offer this slot to anybody */
4659 if (may_dequeue_tasks(t->srv, t->proxy))
4660 task_wakeup(&rq, t->srv->queue_mgt);
4661
willy tarreaudfece232006-05-02 00:19:57 +02004662 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
4663 t->srv = NULL; /* it's left to the dispatcher to choose a server */
4664 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4665 t->flags &= ~SN_CK_MASK;
4666 t->flags |= SN_CK_DOWN;
4667 }
4668 return 0;
4669}
4670
4671/* This function performs the "redispatch" part of a connection attempt. It
4672 * will assign a server if required, queue the connection if required, and
4673 * handle errors that might arise at this level. It can change the server
4674 * state. It will return 1 if it encounters an error, switches the server
4675 * state, or has to queue a connection. Otherwise, it will return 0 indicating
4676 * that the connection is ready to use.
4677 */
4678
4679int srv_redispatch_connect(struct session *t) {
4680 int conn_err;
4681
4682 /* We know that we don't have any connection pending, so we will
4683 * try to get a new one, and wait in this state if it's queued
4684 */
4685 conn_err = assign_server_and_queue(t);
4686 switch (conn_err) {
4687 case SRV_STATUS_OK:
4688 break;
4689
4690 case SRV_STATUS_NOSRV:
willy tarreau59a6cc22006-05-12 01:29:08 +02004691 /* note: it is guaranteed that t->srv == NULL here */
willy tarreaudfece232006-05-02 00:19:57 +02004692 tv_eternity(&t->cnexpire);
4693 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
4694 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaudfece232006-05-02 00:19:57 +02004695 return 1;
4696
4697 case SRV_STATUS_QUEUED:
willy tarreau45526ed2006-05-03 20:11:50 +02004698 /* FIXME-20060503 : we should use the queue timeout instead */
4699 if (t->proxy->contimeout)
4700 tv_delayfrom(&t->cnexpire, &now, t->proxy->contimeout);
4701 else
4702 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02004703 t->srv_state = SV_STIDLE;
4704 /* do nothing else and do not wake any other session up */
4705 return 1;
4706
4707 case SRV_STATUS_FULL:
4708 case SRV_STATUS_INTERNAL:
4709 default:
4710 tv_eternity(&t->cnexpire);
4711 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4712 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4713 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02004714 if (may_dequeue_tasks(t->srv, t->proxy))
4715 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004716 return 1;
4717 }
4718 /* if we get here, it's because we got SRV_STATUS_OK, which also
4719 * means that the connection has not been queued.
4720 */
4721 return 0;
4722}
4723
4724
4725/*
willy tarreau0f7af912005-12-17 12:21:26 +01004726 * manages the server FSM and its socket. It returns 1 if a state has changed
4727 * (and a resync may be needed), 0 else.
4728 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004729int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004730 int s = t->srv_state;
4731 int c = t->cli_state;
4732 struct buffer *req = t->req;
4733 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004734 appsess *asession_temp = NULL;
4735 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004736 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004737
willy tarreau750a4722005-12-17 13:21:24 +01004738#ifdef DEBUG_FULL
4739 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4740#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004741 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4742 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4743 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4744 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004745 if (s == SV_STIDLE) {
4746 if (c == CL_STHEADERS)
4747 return 0; /* stay in idle, waiting for data to reach the client side */
4748 else if (c == CL_STCLOSE ||
4749 c == CL_STSHUTW ||
4750 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4751 tv_eternity(&t->cnexpire);
willy tarreau078c79a2006-05-13 12:23:58 +02004752 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
4753 srv_close_with_err(t, SN_ERR_CLICL, t->pend_pos ? SN_FINST_Q : SN_FINST_C, 0, 0, NULL);
willy tarreaudfece232006-05-02 00:19:57 +02004754
willy tarreau0f7af912005-12-17 12:21:26 +01004755 return 1;
4756 }
willy tarreaudfece232006-05-02 00:19:57 +02004757 else {
4758 /* Right now, we will need to create a connection to the server.
4759 * We might already have tried, and got a connection pending, in
4760 * which case we will not do anything till it's pending. It's up
4761 * to any other session to release it and wake us up again.
4762 */
willy tarreau45526ed2006-05-03 20:11:50 +02004763 if (t->pend_pos) {
4764 if (tv_cmp2_ms(&t->cnexpire, &now) > 0)
4765 return 0;
4766 else {
4767 /* we've been waiting too long here */
4768 tv_eternity(&t->cnexpire);
willy tarreau078c79a2006-05-13 12:23:58 +02004769 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
4770 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
willy tarreau45526ed2006-05-03 20:11:50 +02004771 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4772 return 1;
4773 }
4774 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004775
willy tarreaudfece232006-05-02 00:19:57 +02004776 do {
4777 /* first, get a connection */
4778 if (srv_redispatch_connect(t))
4779 return t->srv_state != SV_STIDLE;
4780
4781 /* try to (re-)connect to the server, and fail if we expire the
4782 * number of retries.
4783 */
willy tarreauf32f5242006-05-02 22:54:52 +02004784 if (srv_retryable_connect(t)) {
4785 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02004786 return t->srv_state != SV_STIDLE;
willy tarreauf32f5242006-05-02 22:54:52 +02004787 }
willy tarreaudfece232006-05-02 00:19:57 +02004788
4789 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004790 }
4791 }
4792 else if (s == SV_STCONN) { /* connection in progress */
4793 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004794 //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 +01004795 return 0; /* nothing changed */
4796 }
4797 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
willy tarreaudfece232006-05-02 00:19:57 +02004798 /* timeout, asynchronous connect error or first write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004799 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
willy tarreaudfece232006-05-02 00:19:57 +02004800
willy tarreau0f7af912005-12-17 12:21:26 +01004801 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004802 if (t->srv)
4803 t->srv->cur_sess--;
willy tarreaudfece232006-05-02 00:19:57 +02004804
4805 if (t->res_sw == RES_SILENT)
willy tarreaub1285d52005-12-18 01:20:14 +01004806 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4807 else
willy tarreaudfece232006-05-02 00:19:57 +02004808 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
willy tarreaub1285d52005-12-18 01:20:14 +01004809
willy tarreaudfece232006-05-02 00:19:57 +02004810 /* ensure that we have enough retries left */
4811 if (srv_count_retry_down(t, conn_err))
4812 return 1;
4813
4814 do {
4815 /* Now we will try to either reconnect to the same server or
4816 * connect to another server. If the connection gets queued
4817 * because all servers are saturated, then we will go back to
4818 * the SV_STIDLE state.
4819 */
willy tarreauf32f5242006-05-02 22:54:52 +02004820 if (srv_retryable_connect(t)) {
4821 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02004822 return t->srv_state != SV_STCONN;
willy tarreauf32f5242006-05-02 22:54:52 +02004823 }
willy tarreaudfece232006-05-02 00:19:57 +02004824
4825 /* we need to redispatch the connection to another server */
4826 if (srv_redispatch_connect(t))
4827 return t->srv_state != SV_STCONN;
4828 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004829 }
4830 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004831 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004832
willy tarreau0f7af912005-12-17 12:21:26 +01004833 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004834 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004835 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004836 tv_eternity(&t->swexpire);
4837 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004838 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004839 if (t->proxy->srvtimeout) {
4840 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004841 /* FIXME: to prevent the server from expiring read timeouts during writes,
4842 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004843 t->srexpire = t->swexpire;
4844 }
4845 else
4846 tv_eternity(&t->swexpire);
4847 }
willy tarreau0f7af912005-12-17 12:21:26 +01004848
4849 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4850 FD_SET(t->srv_fd, StaticReadEvent);
4851 if (t->proxy->srvtimeout)
4852 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4853 else
4854 tv_eternity(&t->srexpire);
4855
4856 t->srv_state = SV_STDATA;
willy tarreau14b4d432006-04-07 18:23:29 +02004857 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004858 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004859
4860 /* if the user wants to log as soon as possible, without counting
4861 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004862 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004863 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4864 sess_log(t);
4865 }
willy tarreau0f7af912005-12-17 12:21:26 +01004866 }
willy tarreauef900ab2005-12-17 12:52:52 +01004867 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004868 t->srv_state = SV_STHEADERS;
willy tarreau14b4d432006-04-07 18:23:29 +02004869 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004870 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4871 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004872 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004873 return 1;
4874 }
4875 }
4876 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004877 /* now parse the partial (or complete) headers */
4878 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4879 char *ptr;
4880 int delete_header;
4881
4882 ptr = rep->lr;
4883
4884 /* look for the end of the current header */
4885 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4886 ptr++;
4887
4888 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004889 int line, len;
4890
4891 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004892
4893 /* first, we'll block if security checks have caught nasty things */
4894 if (t->flags & SN_CACHEABLE) {
4895 if ((t->flags & SN_CACHE_COOK) &&
4896 (t->flags & SN_SCK_ANY) &&
4897 (t->proxy->options & PR_O_CHK_CACHE)) {
4898
4899 /* we're in presence of a cacheable response containing
4900 * a set-cookie header. We'll block it as requested by
4901 * the 'checkcache' option, and send an alert.
4902 */
4903 tv_eternity(&t->srexpire);
4904 tv_eternity(&t->swexpire);
4905 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004906 if (t->srv)
4907 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01004908 t->srv_state = SV_STCLOSE;
4909 t->logs.status = 502;
4910 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4911 if (!(t->flags & SN_ERR_MASK))
4912 t->flags |= SN_ERR_PRXCOND;
4913 if (!(t->flags & SN_FINST_MASK))
4914 t->flags |= SN_FINST_H;
4915
4916 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4917 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4918
willy tarreaudfece232006-05-02 00:19:57 +02004919 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02004920 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02004921 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004922 if (may_dequeue_tasks(t->srv, t->proxy))
4923 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004924
willy tarreau97f58572005-12-18 00:53:44 +01004925 return 1;
4926 }
4927 }
4928
willy tarreau982249e2005-12-18 00:57:06 +01004929 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4930 if (t->flags & SN_SVDENY) {
4931 tv_eternity(&t->srexpire);
4932 tv_eternity(&t->swexpire);
4933 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004934 if (t->srv)
4935 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01004936 t->srv_state = SV_STCLOSE;
4937 t->logs.status = 502;
4938 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4939 if (!(t->flags & SN_ERR_MASK))
4940 t->flags |= SN_ERR_PRXCOND;
4941 if (!(t->flags & SN_FINST_MASK))
4942 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02004943 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02004944 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02004945 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004946 if (may_dequeue_tasks(t->srv, t->proxy))
4947 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004948
willy tarreau982249e2005-12-18 00:57:06 +01004949 return 1;
4950 }
4951
willy tarreau5cbea6f2005-12-17 12:48:26 +01004952 /* we'll have something else to do here : add new headers ... */
4953
willy tarreaucd878942005-12-17 13:27:43 +01004954 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4955 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004956 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004957 * insert a set-cookie here, except if we want to insert only on POST
willy tarreau4f7a1012006-05-09 23:32:26 +02004958 * requests and this one isn't. Note that servers which don't have cookies
4959 * (eg: some backup servers) will return a full cookie removal request.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004960 */
willy tarreau750a4722005-12-17 13:21:24 +01004961 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004962 t->proxy->cookie_name,
willy tarreau4f7a1012006-05-09 23:32:26 +02004963 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
willy tarreau750a4722005-12-17 13:21:24 +01004964
willy tarreau036e1ce2005-12-17 13:46:33 +01004965 t->flags |= SN_SCK_INSERTED;
4966
willy tarreau750a4722005-12-17 13:21:24 +01004967 /* Here, we will tell an eventual cache on the client side that we don't
4968 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4969 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4970 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4971 */
willy tarreau240afa62005-12-17 13:14:35 +01004972 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004973 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4974 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004975
4976 if (rep->data + rep->l < rep->h)
4977 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4978 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004979 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004980 }
4981
4982 /* headers to be added */
4983 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004984 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4985 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004986 }
4987
willy tarreau25c4ea52005-12-18 00:49:49 +01004988 /* add a "connection: close" line if needed */
4989 if (t->proxy->options & PR_O_HTTP_CLOSE)
4990 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4991
willy tarreau5cbea6f2005-12-17 12:48:26 +01004992 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004993 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004994 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004995
Willy TARREAU767ba712006-03-01 22:40:50 +01004996 /* client connection already closed or option 'httpclose' required :
4997 * we close the server's outgoing connection right now.
4998 */
4999 if ((req->l == 0) &&
5000 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
5001 FD_CLR(t->srv_fd, StaticWriteEvent);
5002 tv_eternity(&t->swexpire);
5003
5004 /* We must ensure that the read part is still alive when switching
5005 * to shutw */
5006 FD_SET(t->srv_fd, StaticReadEvent);
5007 if (t->proxy->srvtimeout)
5008 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5009
5010 shutdown(t->srv_fd, SHUT_WR);
5011 t->srv_state = SV_STSHUTW;
5012 }
5013
willy tarreau25c4ea52005-12-18 00:49:49 +01005014 /* if the user wants to log as soon as possible, without counting
5015 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005016 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005017 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
5018 t->logs.bytes = rep->h - rep->data;
5019 sess_log(t);
5020 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005021 break;
5022 }
5023
5024 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
5025 if (ptr > rep->r - 2) {
5026 /* this is a partial header, let's wait for more to come */
5027 rep->lr = ptr;
5028 break;
5029 }
5030
5031 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
5032 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
5033
5034 /* now we know that *ptr is either \r or \n,
5035 * and that there are at least 1 char after it.
5036 */
5037 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
5038 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
5039 else
5040 rep->lr = ptr + 2; /* \r\n or \n\r */
5041
5042 /*
5043 * now we know that we have a full header ; we can do whatever
5044 * we want with these pointers :
5045 * rep->h = beginning of header
5046 * ptr = end of header (first \r or \n)
5047 * rep->lr = beginning of next line (next rep->h)
5048 * rep->r = end of data (not used at this stage)
5049 */
5050
willy tarreaua1598082005-12-17 13:08:06 +01005051
willy tarreau982249e2005-12-18 00:57:06 +01005052 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01005053 t->logs.logwait &= ~LW_RESP;
5054 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01005055 switch (t->logs.status) {
5056 case 200:
5057 case 203:
5058 case 206:
5059 case 300:
5060 case 301:
5061 case 410:
5062 /* RFC2616 @13.4:
5063 * "A response received with a status code of
5064 * 200, 203, 206, 300, 301 or 410 MAY be stored
5065 * by a cache (...) unless a cache-control
5066 * directive prohibits caching."
5067 *
5068 * RFC2616 @9.5: POST method :
5069 * "Responses to this method are not cacheable,
5070 * unless the response includes appropriate
5071 * Cache-Control or Expires header fields."
5072 */
5073 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
5074 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
5075 break;
5076 default:
5077 break;
5078 }
willy tarreau4302f492005-12-18 01:00:37 +01005079 }
5080 else if (t->logs.logwait & LW_RSPHDR) {
5081 struct cap_hdr *h;
5082 int len;
5083 for (h = t->proxy->rsp_cap; h; h = h->next) {
5084 if ((h->namelen + 2 <= ptr - rep->h) &&
5085 (rep->h[h->namelen] == ':') &&
5086 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
5087
5088 if (t->rsp_cap[h->index] == NULL)
5089 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
5090
5091 len = ptr - (rep->h + h->namelen + 2);
5092 if (len > h->len)
5093 len = h->len;
5094
5095 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
5096 t->rsp_cap[h->index][len]=0;
5097 }
5098 }
5099
willy tarreaua1598082005-12-17 13:08:06 +01005100 }
5101
willy tarreau5cbea6f2005-12-17 12:48:26 +01005102 delete_header = 0;
5103
willy tarreau982249e2005-12-18 00:57:06 +01005104 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005105 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01005106 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 +01005107 max = ptr - rep->h;
5108 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01005109 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005110 trash[len++] = '\n';
5111 write(1, trash, len);
5112 }
5113
willy tarreau25c4ea52005-12-18 00:49:49 +01005114 /* remove "connection: " if needed */
5115 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
5116 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
5117 delete_header = 1;
5118 }
5119
willy tarreau5cbea6f2005-12-17 12:48:26 +01005120 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01005121 if (!delete_header && t->proxy->rsp_exp != NULL
5122 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01005123 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005124 char term;
5125
5126 term = *ptr;
5127 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01005128 exp = t->proxy->rsp_exp;
5129 do {
5130 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
5131 switch (exp->action) {
5132 case ACT_ALLOW:
5133 if (!(t->flags & SN_SVDENY))
5134 t->flags |= SN_SVALLOW;
5135 break;
5136 case ACT_REPLACE:
5137 if (!(t->flags & SN_SVDENY)) {
5138 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
5139 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
5140 }
5141 break;
5142 case ACT_REMOVE:
5143 if (!(t->flags & SN_SVDENY))
5144 delete_header = 1;
5145 break;
5146 case ACT_DENY:
5147 if (!(t->flags & SN_SVALLOW))
5148 t->flags |= SN_SVDENY;
5149 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01005150 case ACT_PASS: /* we simply don't deny this one */
5151 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005152 }
5153 break;
5154 }
willy tarreaue39cd132005-12-17 13:00:18 +01005155 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005156 *ptr = term; /* restore the string terminator */
5157 }
5158
willy tarreau97f58572005-12-18 00:53:44 +01005159 /* check for cache-control: or pragma: headers */
5160 if (!delete_header && (t->flags & SN_CACHEABLE)) {
5161 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
5162 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5163 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
5164 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01005165 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01005166 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5167 else {
5168 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01005169 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005170 t->flags &= ~SN_CACHE_COOK;
5171 }
5172 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005173 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005174 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005175 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01005176 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5177 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005178 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01005179 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01005180 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
5181 (rep->h + 25 == ptr || rep->h[25] == ',')) {
5182 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5183 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
5184 (rep->h + 21 == ptr || rep->h[21] == ',')) {
5185 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01005186 }
5187 }
5188 }
5189
willy tarreau5cbea6f2005-12-17 12:48:26 +01005190 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01005191 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01005192 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01005193 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005194 char *p1, *p2, *p3, *p4;
5195
willy tarreau97f58572005-12-18 00:53:44 +01005196 t->flags |= SN_SCK_ANY;
5197
willy tarreau5cbea6f2005-12-17 12:48:26 +01005198 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
5199
5200 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01005201 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005202 p1++;
5203
5204 if (p1 == ptr || *p1 == ';') /* end of cookie */
5205 break;
5206
5207 /* p1 is at the beginning of the cookie name */
5208 p2 = p1;
5209
5210 while (p2 < ptr && *p2 != '=' && *p2 != ';')
5211 p2++;
5212
5213 if (p2 == ptr || *p2 == ';') /* next cookie */
5214 break;
5215
5216 p3 = p2 + 1; /* skips the '=' sign */
5217 if (p3 == ptr)
5218 break;
5219
5220 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01005221 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01005222 p4++;
5223
5224 /* here, we have the cookie name between p1 and p2,
5225 * and its value between p3 and p4.
5226 * we can process it.
5227 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005228
5229 /* first, let's see if we want to capture it */
5230 if (t->proxy->capture_name != NULL &&
5231 t->logs.srv_cookie == NULL &&
5232 (p4 - p1 >= t->proxy->capture_namelen) &&
5233 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
5234 int log_len = p4 - p1;
5235
5236 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
5237 Alert("HTTP logging : out of memory.\n");
5238 }
5239
5240 if (log_len > t->proxy->capture_len)
5241 log_len = t->proxy->capture_len;
5242 memcpy(t->logs.srv_cookie, p1, log_len);
5243 t->logs.srv_cookie[log_len] = 0;
5244 }
5245
5246 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
5247 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005248 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01005249 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005250
5251 /* If the cookie is in insert mode on a known server, we'll delete
5252 * this occurrence because we'll insert another one later.
5253 * We'll delete it too if the "indirect" option is set and we're in
5254 * a direct access. */
5255 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01005256 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005257 /* this header must be deleted */
5258 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01005259 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005260 }
5261 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
5262 /* replace bytes p3->p4 with the cookie name associated
5263 * with this server since we know it.
5264 */
5265 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01005266 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005267 }
willy tarreau0174f312005-12-18 01:02:42 +01005268 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
5269 /* insert the cookie name associated with this server
5270 * before existing cookie, and insert a delimitor between them..
5271 */
5272 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
5273 p3[t->srv->cklen] = COOKIE_DELIM;
5274 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
5275 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005276 break;
5277 }
willy tarreau12350152005-12-18 01:03:27 +01005278
5279 /* first, let's see if the cookie is our appcookie*/
5280 if ((t->proxy->appsession_name != NULL) &&
5281 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
5282
5283 /* Cool... it's the right one */
5284
willy tarreaub952e1d2005-12-18 01:31:20 +01005285 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01005286 asession_temp = &local_asession;
5287
willy tarreaub952e1d2005-12-18 01:31:20 +01005288 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005289 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5290 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5291 }
5292 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
5293 asession_temp->sessid[t->proxy->appsession_len] = 0;
5294 asession_temp->serverid = NULL;
5295
5296 /* only do insert, if lookup fails */
5297 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
5298 if ((asession_temp = pool_alloc(appsess)) == NULL) {
5299 Alert("Not enought Memory process_srv():asession:calloc().\n");
5300 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
5301 return 0;
5302 }
5303 asession_temp->sessid = local_asession.sessid;
5304 asession_temp->serverid = local_asession.serverid;
5305 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01005306 }/* end if (chtbl_lookup()) */
5307 else {
willy tarreau12350152005-12-18 01:03:27 +01005308 /* free wasted memory */
5309 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01005310 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01005311
willy tarreaub952e1d2005-12-18 01:31:20 +01005312 if (asession_temp->serverid == NULL) {
5313 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005314 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5315 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5316 }
5317 asession_temp->serverid[0] = '\0';
5318 }
5319
willy tarreaub952e1d2005-12-18 01:31:20 +01005320 if (asession_temp->serverid[0] == '\0')
5321 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01005322
5323 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
5324
5325#if defined(DEBUG_HASH)
5326 print_table(&(t->proxy->htbl_proxy));
5327#endif
5328 break;
5329 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005330 else {
5331 // fprintf(stderr,"Ignoring unknown cookie : ");
5332 // write(2, p1, p2-p1);
5333 // fprintf(stderr," = ");
5334 // write(2, p3, p4-p3);
5335 // fprintf(stderr,"\n");
5336 }
5337 break; /* we don't want to loop again since there cannot be another cookie on the same line */
5338 } /* we're now at the end of the cookie value */
5339 } /* end of cookie processing */
5340
willy tarreau97f58572005-12-18 00:53:44 +01005341 /* check for any set-cookie in case we check for cacheability */
5342 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
5343 (t->proxy->options & PR_O_CHK_CACHE) &&
5344 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
5345 t->flags |= SN_SCK_ANY;
5346 }
5347
willy tarreau5cbea6f2005-12-17 12:48:26 +01005348 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01005349 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005350 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01005351
willy tarreau5cbea6f2005-12-17 12:48:26 +01005352 rep->h = rep->lr;
5353 } /* while (rep->lr < rep->r) */
5354
5355 /* end of header processing (even if incomplete) */
5356
willy tarreauef900ab2005-12-17 12:52:52 +01005357 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5358 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
5359 * full. We cannot loop here since event_srv_read will disable it only if
5360 * rep->l == rlim-data
5361 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005362 FD_SET(t->srv_fd, StaticReadEvent);
5363 if (t->proxy->srvtimeout)
5364 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5365 else
5366 tv_eternity(&t->srexpire);
5367 }
willy tarreau0f7af912005-12-17 12:21:26 +01005368
willy tarreau8337c6b2005-12-17 13:41:01 +01005369 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005370 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005371 tv_eternity(&t->srexpire);
5372 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005373 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005374 if (t->srv)
5375 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005376 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01005377 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01005378 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01005379 if (!(t->flags & SN_ERR_MASK))
5380 t->flags |= SN_ERR_SRVCL;
5381 if (!(t->flags & SN_FINST_MASK))
5382 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005383 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005384 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005385 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005386 if (may_dequeue_tasks(t->srv, t->proxy))
5387 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005388
willy tarreau0f7af912005-12-17 12:21:26 +01005389 return 1;
5390 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005391 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01005392 * since we are in header mode, if there's no space left for headers, we
5393 * won't be able to free more later, so the session will never terminate.
5394 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005395 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 +01005396 FD_CLR(t->srv_fd, StaticReadEvent);
5397 tv_eternity(&t->srexpire);
5398 shutdown(t->srv_fd, SHUT_RD);
5399 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005400 //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 +01005401 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01005402 }
5403 /* read timeout : return a 504 to the client.
5404 */
5405 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5406 tv_eternity(&t->srexpire);
5407 tv_eternity(&t->swexpire);
5408 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005409 if (t->srv)
5410 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01005411 t->srv_state = SV_STCLOSE;
5412 t->logs.status = 504;
5413 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01005414 if (!(t->flags & SN_ERR_MASK))
5415 t->flags |= SN_ERR_SRVTO;
5416 if (!(t->flags & SN_FINST_MASK))
5417 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005418 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005419 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005420 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005421 if (may_dequeue_tasks(t->srv, t->proxy))
5422 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005423
willy tarreau8337c6b2005-12-17 13:41:01 +01005424 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005425 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005426 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01005427 /* FIXME!!! here, we don't want to switch to SHUTW if the
5428 * client shuts read too early, because we may still have
5429 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01005430 * The side-effect is that if the client completely closes its
5431 * connection during SV_STHEADER, the connection to the server
5432 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01005433 */
willy tarreau036e1ce2005-12-17 13:46:33 +01005434 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005435 FD_CLR(t->srv_fd, StaticWriteEvent);
5436 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01005437
5438 /* We must ensure that the read part is still alive when switching
5439 * to shutw */
5440 FD_SET(t->srv_fd, StaticReadEvent);
5441 if (t->proxy->srvtimeout)
5442 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5443
willy tarreau0f7af912005-12-17 12:21:26 +01005444 shutdown(t->srv_fd, SHUT_WR);
5445 t->srv_state = SV_STSHUTW;
5446 return 1;
5447 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005448 /* write timeout */
5449 /* FIXME!!! here, we don't want to switch to SHUTW if the
5450 * client shuts read too early, because we may still have
5451 * some work to do on the headers.
5452 */
5453 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5454 FD_CLR(t->srv_fd, StaticWriteEvent);
5455 tv_eternity(&t->swexpire);
5456 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005457 /* We must ensure that the read part is still alive when switching
5458 * to shutw */
5459 FD_SET(t->srv_fd, StaticReadEvent);
5460 if (t->proxy->srvtimeout)
5461 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5462
5463 /* We must ensure that the read part is still alive when switching
5464 * to shutw */
5465 FD_SET(t->srv_fd, StaticReadEvent);
5466 if (t->proxy->srvtimeout)
5467 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5468
willy tarreau036e1ce2005-12-17 13:46:33 +01005469 t->srv_state = SV_STSHUTW;
5470 if (!(t->flags & SN_ERR_MASK))
5471 t->flags |= SN_ERR_SRVTO;
5472 if (!(t->flags & SN_FINST_MASK))
5473 t->flags |= SN_FINST_H;
5474 return 1;
5475 }
willy tarreau0f7af912005-12-17 12:21:26 +01005476
5477 if (req->l == 0) {
5478 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5479 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5480 tv_eternity(&t->swexpire);
5481 }
5482 }
5483 else { /* client buffer not empty */
5484 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5485 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005486 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005487 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005488 /* FIXME: to prevent the server from expiring read timeouts during writes,
5489 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005490 t->srexpire = t->swexpire;
5491 }
willy tarreau0f7af912005-12-17 12:21:26 +01005492 else
5493 tv_eternity(&t->swexpire);
5494 }
5495 }
5496
willy tarreau5cbea6f2005-12-17 12:48:26 +01005497 /* be nice with the client side which would like to send a complete header
5498 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
5499 * would read all remaining data at once ! The client should not write past rep->lr
5500 * when the server is in header state.
5501 */
5502 //return header_processed;
5503 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01005504 }
5505 else if (s == SV_STDATA) {
5506 /* read or write error */
5507 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005508 tv_eternity(&t->srexpire);
5509 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005510 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005511 if (t->srv)
5512 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005513 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005514 if (!(t->flags & SN_ERR_MASK))
5515 t->flags |= SN_ERR_SRVCL;
5516 if (!(t->flags & SN_FINST_MASK))
5517 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005518 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005519 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005520 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005521 if (may_dequeue_tasks(t->srv, t->proxy))
5522 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005523
willy tarreau0f7af912005-12-17 12:21:26 +01005524 return 1;
5525 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005526 /* last read, or end of client write */
5527 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005528 FD_CLR(t->srv_fd, StaticReadEvent);
5529 tv_eternity(&t->srexpire);
5530 shutdown(t->srv_fd, SHUT_RD);
5531 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005532 //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 +01005533 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01005534 }
5535 /* end of client read and no more data to send */
5536 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
5537 FD_CLR(t->srv_fd, StaticWriteEvent);
5538 tv_eternity(&t->swexpire);
5539 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005540 /* We must ensure that the read part is still alive when switching
5541 * to shutw */
5542 FD_SET(t->srv_fd, StaticReadEvent);
5543 if (t->proxy->srvtimeout)
5544 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5545
willy tarreaua41a8b42005-12-17 14:02:24 +01005546 t->srv_state = SV_STSHUTW;
5547 return 1;
5548 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005549 /* read timeout */
5550 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5551 FD_CLR(t->srv_fd, StaticReadEvent);
5552 tv_eternity(&t->srexpire);
5553 shutdown(t->srv_fd, SHUT_RD);
5554 t->srv_state = SV_STSHUTR;
5555 if (!(t->flags & SN_ERR_MASK))
5556 t->flags |= SN_ERR_SRVTO;
5557 if (!(t->flags & SN_FINST_MASK))
5558 t->flags |= SN_FINST_D;
5559 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005560 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005561 /* write timeout */
5562 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005563 FD_CLR(t->srv_fd, StaticWriteEvent);
5564 tv_eternity(&t->swexpire);
5565 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005566 /* We must ensure that the read part is still alive when switching
5567 * to shutw */
5568 FD_SET(t->srv_fd, StaticReadEvent);
5569 if (t->proxy->srvtimeout)
5570 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005571 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01005572 if (!(t->flags & SN_ERR_MASK))
5573 t->flags |= SN_ERR_SRVTO;
5574 if (!(t->flags & SN_FINST_MASK))
5575 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005576 return 1;
5577 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005578
5579 /* recompute request time-outs */
5580 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005581 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5582 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5583 tv_eternity(&t->swexpire);
5584 }
5585 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005586 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01005587 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5588 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005589 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005590 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005591 /* FIXME: to prevent the server from expiring read timeouts during writes,
5592 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005593 t->srexpire = t->swexpire;
5594 }
willy tarreau0f7af912005-12-17 12:21:26 +01005595 else
5596 tv_eternity(&t->swexpire);
5597 }
5598 }
5599
willy tarreaub1ff9db2005-12-17 13:51:03 +01005600 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01005601 if (rep->l == BUFSIZE) { /* no room to read more data */
5602 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5603 FD_CLR(t->srv_fd, StaticReadEvent);
5604 tv_eternity(&t->srexpire);
5605 }
5606 }
5607 else {
5608 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5609 FD_SET(t->srv_fd, StaticReadEvent);
5610 if (t->proxy->srvtimeout)
5611 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5612 else
5613 tv_eternity(&t->srexpire);
5614 }
5615 }
5616
5617 return 0; /* other cases change nothing */
5618 }
5619 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005620 if (t->res_sw == RES_ERROR) {
5621 //FD_CLR(t->srv_fd, StaticWriteEvent);
5622 tv_eternity(&t->swexpire);
5623 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005624 if (t->srv)
5625 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005626 //close(t->srv_fd);
5627 t->srv_state = SV_STCLOSE;
5628 if (!(t->flags & SN_ERR_MASK))
5629 t->flags |= SN_ERR_SRVCL;
5630 if (!(t->flags & SN_FINST_MASK))
5631 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005632 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005633 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005634 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005635 if (may_dequeue_tasks(t->srv, t->proxy))
5636 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005637
willy tarreau036e1ce2005-12-17 13:46:33 +01005638 return 1;
5639 }
5640 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005641 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005642 tv_eternity(&t->swexpire);
5643 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005644 if (t->srv)
5645 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005646 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005647 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02005648 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005649 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005650 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005651 if (may_dequeue_tasks(t->srv, t->proxy))
5652 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005653
willy tarreau0f7af912005-12-17 12:21:26 +01005654 return 1;
5655 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005656 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5657 //FD_CLR(t->srv_fd, StaticWriteEvent);
5658 tv_eternity(&t->swexpire);
5659 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005660 if (t->srv)
5661 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005662 //close(t->srv_fd);
5663 t->srv_state = SV_STCLOSE;
5664 if (!(t->flags & SN_ERR_MASK))
5665 t->flags |= SN_ERR_SRVTO;
5666 if (!(t->flags & SN_FINST_MASK))
5667 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005668 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005669 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005670 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005671 if (may_dequeue_tasks(t->srv, t->proxy))
5672 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005673
willy tarreau036e1ce2005-12-17 13:46:33 +01005674 return 1;
5675 }
willy tarreau0f7af912005-12-17 12:21:26 +01005676 else if (req->l == 0) {
5677 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5678 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5679 tv_eternity(&t->swexpire);
5680 }
5681 }
5682 else { /* buffer not empty */
5683 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5684 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005685 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005686 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005687 /* FIXME: to prevent the server from expiring read timeouts during writes,
5688 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005689 t->srexpire = t->swexpire;
5690 }
willy tarreau0f7af912005-12-17 12:21:26 +01005691 else
5692 tv_eternity(&t->swexpire);
5693 }
5694 }
5695 return 0;
5696 }
5697 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005698 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005699 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005700 tv_eternity(&t->srexpire);
5701 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005702 if (t->srv)
5703 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005704 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005705 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005706 if (!(t->flags & SN_ERR_MASK))
5707 t->flags |= SN_ERR_SRVCL;
5708 if (!(t->flags & SN_FINST_MASK))
5709 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005710 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005711 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005712 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005713 if (may_dequeue_tasks(t->srv, t->proxy))
5714 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005715
willy tarreau0f7af912005-12-17 12:21:26 +01005716 return 1;
5717 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005718 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5719 //FD_CLR(t->srv_fd, StaticReadEvent);
5720 tv_eternity(&t->srexpire);
5721 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005722 if (t->srv)
5723 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005724 //close(t->srv_fd);
5725 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02005726 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005727 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005728 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005729 if (may_dequeue_tasks(t->srv, t->proxy))
5730 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005731
willy tarreau036e1ce2005-12-17 13:46:33 +01005732 return 1;
5733 }
5734 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5735 //FD_CLR(t->srv_fd, StaticReadEvent);
5736 tv_eternity(&t->srexpire);
5737 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005738 if (t->srv)
5739 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005740 //close(t->srv_fd);
5741 t->srv_state = SV_STCLOSE;
5742 if (!(t->flags & SN_ERR_MASK))
5743 t->flags |= SN_ERR_SRVTO;
5744 if (!(t->flags & SN_FINST_MASK))
5745 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005746 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005747 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005748 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005749 if (may_dequeue_tasks(t->srv, t->proxy))
5750 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005751
willy tarreau036e1ce2005-12-17 13:46:33 +01005752 return 1;
5753 }
willy tarreau0f7af912005-12-17 12:21:26 +01005754 else if (rep->l == BUFSIZE) { /* no room to read more data */
5755 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5756 FD_CLR(t->srv_fd, StaticReadEvent);
5757 tv_eternity(&t->srexpire);
5758 }
5759 }
5760 else {
5761 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5762 FD_SET(t->srv_fd, StaticReadEvent);
5763 if (t->proxy->srvtimeout)
5764 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5765 else
5766 tv_eternity(&t->srexpire);
5767 }
5768 }
5769 return 0;
5770 }
5771 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005772 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005773 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005774 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 +01005775 write(1, trash, len);
5776 }
5777 return 0;
5778 }
5779 return 0;
5780}
5781
5782
willy tarreau5cbea6f2005-12-17 12:48:26 +01005783/* Processes the client and server jobs of a session task, then
5784 * puts it back to the wait queue in a clean state, or
5785 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005786 * the time the task accepts to wait, or TIME_ETERNITY for
5787 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005788 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005789int process_session(struct task *t) {
5790 struct session *s = t->context;
5791 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005792
willy tarreau5cbea6f2005-12-17 12:48:26 +01005793 do {
5794 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005795 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005796 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005797 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005798 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005799 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005800 } while (fsm_resync);
5801
5802 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005803 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005804 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005805
willy tarreau5cbea6f2005-12-17 12:48:26 +01005806 tv_min(&min1, &s->crexpire, &s->cwexpire);
5807 tv_min(&min2, &s->srexpire, &s->swexpire);
5808 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005809 tv_min(&t->expire, &min1, &min2);
5810
5811 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005812 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005813
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005814#ifdef DEBUG_FULL
5815 /* DEBUG code : this should never ever happen, otherwise it indicates
5816 * that a task still has something to do and will provoke a quick loop.
5817 */
5818 if (tv_remain2(&now, &t->expire) <= 0)
5819 exit(100);
5820#endif
5821
willy tarreaub952e1d2005-12-18 01:31:20 +01005822 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005823 }
5824
willy tarreau5cbea6f2005-12-17 12:48:26 +01005825 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005826 actconn--;
5827
willy tarreau982249e2005-12-18 00:57:06 +01005828 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005829 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005830 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 +01005831 write(1, trash, len);
5832 }
5833
willy tarreau750a4722005-12-17 13:21:24 +01005834 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005835 if (s->rep != NULL)
5836 s->logs.bytes = s->rep->total;
5837
willy tarreau9fe663a2005-12-17 13:02:59 +01005838 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005839 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005840 sess_log(s);
5841
willy tarreau0f7af912005-12-17 12:21:26 +01005842 /* the task MUST not be in the run queue anymore */
5843 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005844 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005845 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005846 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005847}
5848
5849
willy tarreau2812edc2006-05-04 12:09:37 +02005850/* Sets server <s> down, notifies by all available means, recounts the
5851 * remaining servers on the proxy and transfers queued sessions whenever
5852 * possible to other servers.
5853 */
5854void set_server_down(struct server *s) {
5855 struct pendconn *pc, *pc_bck, *pc_end;
5856 struct session *sess;
5857 int xferred;
5858
5859 s->state &= ~SRV_RUNNING;
5860
5861 if (s->health == s->rise) {
5862 recount_servers(s->proxy);
5863 recalc_server_map(s->proxy);
5864
5865 /* we might have sessions queued on this server and waiting for
5866 * a connection. Those which are redispatchable will be queued
5867 * to another server or to the proxy itself.
5868 */
5869 xferred = 0;
5870 FOREACH_ITEM_SAFE(pc, pc_bck, &s->pendconns, pc_end, struct pendconn *, list) {
5871 sess = pc->sess;
5872 if ((sess->proxy->options & PR_O_REDISP)) {
5873 /* The REDISP option was specified. We will ignore
5874 * cookie and force to balance or use the dispatcher.
5875 */
5876 sess->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
5877 sess->srv = NULL; /* it's left to the dispatcher to choose a server */
5878 if ((sess->flags & SN_CK_MASK) == SN_CK_VALID) {
5879 sess->flags &= ~SN_CK_MASK;
5880 sess->flags |= SN_CK_DOWN;
5881 }
5882 pendconn_free(pc);
5883 task_wakeup(&rq, sess->task);
5884 xferred++;
5885 }
5886 }
5887
5888 sprintf(trash, "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s"
5889 " %d sessions active, %d requeued, %d remaining in queue.\n",
5890 s->state & SRV_BACKUP ? "Backup " : "",
5891 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5892 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
5893 s->cur_sess, xferred, s->nbpend);
5894
willy tarreaubc2eda62006-05-04 15:16:23 +02005895 Warning("%s", trash);
5896 send_log(s->proxy, LOG_ALERT, "%s", trash);
willy tarreau2812edc2006-05-04 12:09:37 +02005897
5898 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5899 Alert("Proxy %s has no server available !\n", s->proxy->id);
5900 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5901 }
5902 }
5903 s->health = 0; /* failure */
5904}
5905
5906
willy tarreau5cbea6f2005-12-17 12:48:26 +01005907
5908/*
5909 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005910 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005911 */
5912int process_chk(struct task *t) {
5913 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005914 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005915 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005916
willy tarreauef900ab2005-12-17 12:52:52 +01005917 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005918
willy tarreau25424f82006-03-19 19:37:48 +01005919 new_chk:
5920 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005921 if (fd < 0) { /* no check currently running */
5922 //fprintf(stderr, "process_chk: 2\n");
5923 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5924 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005925 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005926 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005927
5928 /* we don't send any health-checks when the proxy is stopped or when
5929 * the server should not be checked.
5930 */
5931 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005932 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5933 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005934 task_queue(t); /* restore t to its place in the task list */
5935 return tv_remain2(&now, &t->expire);
5936 }
5937
willy tarreau5cbea6f2005-12-17 12:48:26 +01005938 /* we'll initiate a new check */
5939 s->result = 0; /* no result yet */
5940 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005941 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005942 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5943 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5944 //fprintf(stderr, "process_chk: 3\n");
5945
willy tarreaua41a8b42005-12-17 14:02:24 +01005946 /* we'll connect to the check port on the server */
5947 sa = s->addr;
5948 sa.sin_port = htons(s->check_port);
5949
willy tarreau0174f312005-12-18 01:02:42 +01005950 /* allow specific binding :
5951 * - server-specific at first
5952 * - proxy-specific next
5953 */
5954 if (s->state & SRV_BIND_SRC) {
5955 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5956 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5957 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5958 s->proxy->id, s->id);
5959 s->result = -1;
5960 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005961 }
willy tarreau0174f312005-12-18 01:02:42 +01005962 else if (s->proxy->options & PR_O_BIND_SRC) {
5963 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5964 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5965 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5966 s->proxy->id);
5967 s->result = -1;
5968 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005969 }
willy tarreau0174f312005-12-18 01:02:42 +01005970
5971 if (!s->result) {
5972 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5973 /* OK, connection in progress or established */
5974
5975 //fprintf(stderr, "process_chk: 4\n");
5976
5977 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5978 fdtab[fd].owner = t;
5979 fdtab[fd].read = &event_srv_chk_r;
5980 fdtab[fd].write = &event_srv_chk_w;
5981 fdtab[fd].state = FD_STCONN; /* connection in progress */
5982 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005983#ifdef DEBUG_FULL
5984 assert (!FD_ISSET(fd, StaticReadEvent));
5985#endif
willy tarreau0174f312005-12-18 01:02:42 +01005986 fd_insert(fd);
5987 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5988 tv_delayfrom(&t->expire, &now, s->inter);
5989 task_queue(t); /* restore t to its place in the task list */
5990 return tv_remain(&now, &t->expire);
5991 }
5992 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5993 s->result = -1; /* a real error */
5994 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005995 }
5996 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005997 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005998 }
5999
6000 if (!s->result) { /* nothing done */
6001 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01006002 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6003 tv_delayfrom(&t->expire, &t->expire, s->inter);
6004 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006005 }
6006
6007 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01006008 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01006009 s->health--; /* still good */
willy tarreau2812edc2006-05-04 12:09:37 +02006010 else
6011 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006012
6013 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01006014 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01006015 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6016 tv_delayfrom(&t->expire, &t->expire, s->inter);
6017 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006018 }
6019 else {
6020 //fprintf(stderr, "process_chk: 8\n");
6021 /* there was a test running */
6022 if (s->result > 0) { /* good server detected */
6023 //fprintf(stderr, "process_chk: 9\n");
6024 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01006025 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02006026 s->state |= SRV_RUNNING;
6027
willy tarreau535ae7a2005-12-17 12:58:00 +01006028 if (s->health == s->rise) {
willy tarreaubc2eda62006-05-04 15:16:23 +02006029 int xferred;
6030
willy tarreau62084d42006-03-24 18:57:41 +01006031 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02006032 recalc_server_map(s->proxy);
willy tarreaubc2eda62006-05-04 15:16:23 +02006033
6034 /* check if we can handle some connections queued at the proxy. We
6035 * will take as many as we can handle.
6036 */
6037 for (xferred = 0; !s->maxconn || xferred < s->maxconn; xferred++) {
6038 struct session *sess;
6039 struct pendconn *p;
6040
6041 p = pendconn_from_px(s->proxy);
6042 if (!p)
6043 break;
6044 p->sess->srv = s;
6045 sess = p->sess;
6046 pendconn_free(p);
6047 task_wakeup(&rq, sess->task);
6048 }
6049
6050 sprintf(trash,
6051 "%sServer %s/%s is UP. %d active and %d backup servers online.%s"
6052 " %d sessions requeued, %d total in queue.\n",
6053 s->state & SRV_BACKUP ? "Backup " : "",
6054 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6055 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6056 xferred, s->nbpend);
6057
6058 Warning("%s", trash);
6059 send_log(s->proxy, LOG_NOTICE, "%s", trash);
willy tarreau535ae7a2005-12-17 12:58:00 +01006060 }
willy tarreauef900ab2005-12-17 12:52:52 +01006061
willy tarreaue47c8d72005-12-17 12:55:52 +01006062 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006063 }
willy tarreauef900ab2005-12-17 12:52:52 +01006064 s->curfd = -1; /* no check running anymore */
6065 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006066 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006067 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6068 tv_delayfrom(&t->expire, &t->expire, s->inter);
6069 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006070 }
6071 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
6072 //fprintf(stderr, "process_chk: 10\n");
6073 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01006074 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01006075 s->health--; /* still good */
willy tarreau2812edc2006-05-04 12:09:37 +02006076 else
6077 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006078 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01006079 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006080 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006081 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6082 tv_delayfrom(&t->expire, &t->expire, s->inter);
6083 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006084 }
6085 /* if result is 0 and there's no timeout, we have to wait again */
6086 }
6087 //fprintf(stderr, "process_chk: 11\n");
6088 s->result = 0;
6089 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006090 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01006091}
6092
6093
willy tarreau5cbea6f2005-12-17 12:48:26 +01006094
willy tarreau59a6cc22006-05-12 01:29:08 +02006095/*
6096 * Manages a server's connection queue. If woken up, will try to dequeue as
6097 * many pending sessions as possible, and wake them up. The task has nothing
6098 * else to do, so it always returns TIME_ETERNITY.
6099 */
6100int process_srv_queue(struct task *t) {
6101 struct server *s = (struct server*)t->context;
6102 struct proxy *p = s->proxy;
6103 int xferred;
6104
6105 /* First, check if we can handle some connections queued at the proxy. We
6106 * will take as many as we can handle.
6107 */
6108 for (xferred = 0; s->cur_sess + xferred < s->maxconn; xferred++) {
6109 struct session *sess;
6110
6111 sess = pendconn_get_next_sess(s, p);
6112 if (sess == NULL)
6113 break;
6114 task_wakeup(&rq, sess->task);
6115 }
6116
6117 return TIME_ETERNITY;
6118}
6119
willy tarreau0f7af912005-12-17 12:21:26 +01006120#if STATTIME > 0
6121int stats(void);
6122#endif
6123
6124/*
willy tarreau1c2ad212005-12-18 01:11:29 +01006125 * This does 4 things :
6126 * - wake up all expired tasks
6127 * - call all runnable tasks
6128 * - call maintain_proxies() to enable/disable the listeners
6129 * - return the delay till next event in ms, -1 = wait indefinitely
6130 * Note: this part should be rewritten with the O(ln(n)) scheduler.
6131 *
willy tarreau0f7af912005-12-17 12:21:26 +01006132 */
6133
willy tarreau1c2ad212005-12-18 01:11:29 +01006134int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01006135 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01006136 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006137 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01006138
willy tarreaub952e1d2005-12-18 01:31:20 +01006139 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01006140
willy tarreau1c2ad212005-12-18 01:11:29 +01006141 /* look for expired tasks and add them to the run queue.
6142 */
willy tarreau5e698ef2006-05-02 14:51:00 +02006143 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6144 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau1c2ad212005-12-18 01:11:29 +01006145 tnext = t->next;
6146 if (t->state & TASK_RUNNING)
6147 continue;
6148
willy tarreaub952e1d2005-12-18 01:31:20 +01006149 if (tv_iseternity(&t->expire))
6150 continue;
6151
willy tarreau1c2ad212005-12-18 01:11:29 +01006152 /* wakeup expired entries. It doesn't matter if they are
6153 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01006154 */
willy tarreaub952e1d2005-12-18 01:31:20 +01006155 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006156 task_wakeup(&rq, t);
6157 }
6158 else {
6159 /* first non-runnable task. Use its expiration date as an upper bound */
6160 int temp_time = tv_remain(&now, &t->expire);
6161 if (temp_time)
6162 next_time = temp_time;
6163 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006164 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006165 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006166
willy tarreau1c2ad212005-12-18 01:11:29 +01006167 /* process each task in the run queue now. Each task may be deleted
willy tarreau7feab592006-04-22 15:13:16 +02006168 * since we only use the run queue's head. Note that any task can be
6169 * woken up by any other task and it will be processed immediately
6170 * after as it will be queued on the run queue's head.
willy tarreau1c2ad212005-12-18 01:11:29 +01006171 */
willy tarreau7feab592006-04-22 15:13:16 +02006172 while ((t = rq) != NULL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006173 int temp_time;
willy tarreau7feab592006-04-22 15:13:16 +02006174
willy tarreau1c2ad212005-12-18 01:11:29 +01006175 task_sleep(&rq, t);
6176 temp_time = t->process(t);
6177 next_time = MINTIME(temp_time, next_time);
6178 }
6179
6180 /* maintain all proxies in a consistent state. This should quickly become a task */
6181 time2 = maintain_proxies();
6182 return MINTIME(time2, next_time);
6183}
6184
6185
6186#if defined(ENABLE_EPOLL)
6187
6188/*
6189 * Main epoll() loop.
6190 */
6191
6192/* does 3 actions :
6193 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6194 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6195 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6196 *
6197 * returns 0 if initialization failed, !0 otherwise.
6198 */
6199
6200int epoll_loop(int action) {
6201 int next_time;
6202 int status;
6203 int fd;
6204
6205 int fds, count;
6206 int pr, pw, sr, sw;
6207 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
6208 struct epoll_event ev;
6209
6210 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01006211 static struct epoll_event *epoll_events = NULL;
6212 static int epoll_fd;
6213
6214 if (action == POLL_LOOP_ACTION_INIT) {
6215 epoll_fd = epoll_create(global.maxsock + 1);
6216 if (epoll_fd < 0)
6217 return 0;
6218 else {
6219 epoll_events = (struct epoll_event*)
6220 calloc(1, sizeof(struct epoll_event) * global.maxsock);
6221 PrevReadEvent = (fd_set *)
6222 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6223 PrevWriteEvent = (fd_set *)
6224 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006225 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006226 return 1;
6227 }
6228 else if (action == POLL_LOOP_ACTION_CLEAN) {
6229 if (PrevWriteEvent) free(PrevWriteEvent);
6230 if (PrevReadEvent) free(PrevReadEvent);
6231 if (epoll_events) free(epoll_events);
6232 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01006233 epoll_fd = 0;
6234 return 1;
6235 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006236
willy tarreau1c2ad212005-12-18 01:11:29 +01006237 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006238
willy tarreau1c2ad212005-12-18 01:11:29 +01006239 tv_now(&now);
6240
6241 while (1) {
6242 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01006243
6244 /* stop when there's no connection left and we don't allow them anymore */
6245 if (!actconn && listeners == 0)
6246 break;
6247
willy tarreau0f7af912005-12-17 12:21:26 +01006248#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01006249 {
6250 int time2;
6251 time2 = stats();
6252 next_time = MINTIME(time2, next_time);
6253 }
willy tarreau0f7af912005-12-17 12:21:26 +01006254#endif
6255
willy tarreau1c2ad212005-12-18 01:11:29 +01006256 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6257
6258 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
6259 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
6260
6261 if ((ro^rn) | (wo^wn)) {
6262 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6263#define FDSETS_ARE_INT_ALIGNED
6264#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01006265
willy tarreauad90a0c2005-12-18 01:09:15 +01006266#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6267#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01006268 pr = (ro >> count) & 1;
6269 pw = (wo >> count) & 1;
6270 sr = (rn >> count) & 1;
6271 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01006272#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006273 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
6274 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
6275 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6276 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01006277#endif
6278#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006279 pr = FD_ISSET(fd, PrevReadEvent);
6280 pw = FD_ISSET(fd, PrevWriteEvent);
6281 sr = FD_ISSET(fd, StaticReadEvent);
6282 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01006283#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01006284 if (!((sr^pr) | (sw^pw)))
6285 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01006286
willy tarreau1c2ad212005-12-18 01:11:29 +01006287 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
6288 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01006289
willy tarreaub952e1d2005-12-18 01:31:20 +01006290#ifdef EPOLL_CTL_MOD_WORKAROUND
6291 /* I encountered a rarely reproducible problem with
6292 * EPOLL_CTL_MOD where a modified FD (systematically
6293 * the one in epoll_events[0], fd#7) would sometimes
6294 * be set EPOLL_OUT while asked for a read ! This is
6295 * with the 2.4 epoll patch. The workaround is to
6296 * delete then recreate in case of modification.
6297 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
6298 * nor RHEL kernels.
6299 */
6300
6301 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
6302 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
6303
6304 if ((sr | sw))
6305 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
6306#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006307 if ((pr | pw)) {
6308 /* the file-descriptor already exists... */
6309 if ((sr | sw)) {
6310 /* ...and it will still exist */
6311 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
6312 // perror("epoll_ctl(MOD)");
6313 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006314 }
6315 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01006316 /* ...and it will be removed */
6317 if (fdtab[fd].state != FD_STCLOSE &&
6318 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
6319 // perror("epoll_ctl(DEL)");
6320 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006321 }
6322 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006323 } else {
6324 /* the file-descriptor did not exist, let's add it */
6325 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
6326 // perror("epoll_ctl(ADD)");
6327 // exit(1);
6328 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006329 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006330#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01006331 }
6332 ((int*)PrevReadEvent)[fds] = rn;
6333 ((int*)PrevWriteEvent)[fds] = wn;
6334 }
6335 }
6336
6337 /* now let's wait for events */
6338 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
6339 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006340
willy tarreau1c2ad212005-12-18 01:11:29 +01006341 for (count = 0; count < status; count++) {
6342 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01006343
6344 if (FD_ISSET(fd, StaticReadEvent)) {
6345 if (fdtab[fd].state == FD_STCLOSE)
6346 continue;
6347 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
6348 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006349 }
willy tarreau05be12b2006-03-19 19:35:00 +01006350
6351 if (FD_ISSET(fd, StaticWriteEvent)) {
6352 if (fdtab[fd].state == FD_STCLOSE)
6353 continue;
6354 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
6355 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006356 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006357 }
6358 }
6359 return 1;
6360}
6361#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006362
willy tarreauad90a0c2005-12-18 01:09:15 +01006363
willy tarreau5cbea6f2005-12-17 12:48:26 +01006364
willy tarreau1c2ad212005-12-18 01:11:29 +01006365#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01006366
willy tarreau1c2ad212005-12-18 01:11:29 +01006367/*
6368 * Main poll() loop.
6369 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006370
willy tarreau1c2ad212005-12-18 01:11:29 +01006371/* does 3 actions :
6372 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6373 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6374 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6375 *
6376 * returns 0 if initialization failed, !0 otherwise.
6377 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006378
willy tarreau1c2ad212005-12-18 01:11:29 +01006379int poll_loop(int action) {
6380 int next_time;
6381 int status;
6382 int fd, nbfd;
6383
6384 int fds, count;
6385 int sr, sw;
6386 unsigned rn, wn; /* read new, write new */
6387
6388 /* private data */
6389 static struct pollfd *poll_events = NULL;
6390
6391 if (action == POLL_LOOP_ACTION_INIT) {
6392 poll_events = (struct pollfd*)
6393 calloc(1, sizeof(struct pollfd) * global.maxsock);
6394 return 1;
6395 }
6396 else if (action == POLL_LOOP_ACTION_CLEAN) {
6397 if (poll_events)
6398 free(poll_events);
6399 return 1;
6400 }
6401
6402 /* OK, it's POLL_LOOP_ACTION_RUN */
6403
6404 tv_now(&now);
6405
6406 while (1) {
6407 next_time = process_runnable_tasks();
6408
6409 /* stop when there's no connection left and we don't allow them anymore */
6410 if (!actconn && listeners == 0)
6411 break;
6412
6413#if STATTIME > 0
6414 {
6415 int time2;
6416 time2 = stats();
6417 next_time = MINTIME(time2, next_time);
6418 }
6419#endif
6420
6421
6422 nbfd = 0;
6423 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6424
6425 rn = ((int*)StaticReadEvent)[fds];
6426 wn = ((int*)StaticWriteEvent)[fds];
6427
6428 if ((rn|wn)) {
6429 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6430#define FDSETS_ARE_INT_ALIGNED
6431#ifdef FDSETS_ARE_INT_ALIGNED
6432
6433#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6434#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6435 sr = (rn >> count) & 1;
6436 sw = (wn >> count) & 1;
6437#else
6438 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6439 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
6440#endif
6441#else
6442 sr = FD_ISSET(fd, StaticReadEvent);
6443 sw = FD_ISSET(fd, StaticWriteEvent);
6444#endif
6445 if ((sr|sw)) {
6446 poll_events[nbfd].fd = fd;
6447 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
6448 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01006449 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006450 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006451 }
6452 }
6453
6454 /* now let's wait for events */
6455 status = poll(poll_events, nbfd, next_time);
6456 tv_now(&now);
6457
6458 for (count = 0; status > 0 && count < nbfd; count++) {
6459 fd = poll_events[count].fd;
6460
6461 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
6462 continue;
6463
6464 /* ok, we found one active fd */
6465 status--;
6466
willy tarreau05be12b2006-03-19 19:35:00 +01006467 if (FD_ISSET(fd, StaticReadEvent)) {
6468 if (fdtab[fd].state == FD_STCLOSE)
6469 continue;
6470 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
6471 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006472 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006473
willy tarreau05be12b2006-03-19 19:35:00 +01006474 if (FD_ISSET(fd, StaticWriteEvent)) {
6475 if (fdtab[fd].state == FD_STCLOSE)
6476 continue;
6477 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
6478 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006479 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006480 }
6481 }
6482 return 1;
6483}
willy tarreauad90a0c2005-12-18 01:09:15 +01006484#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006485
willy tarreauad90a0c2005-12-18 01:09:15 +01006486
willy tarreauad90a0c2005-12-18 01:09:15 +01006487
willy tarreau1c2ad212005-12-18 01:11:29 +01006488/*
6489 * Main select() loop.
6490 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006491
willy tarreau1c2ad212005-12-18 01:11:29 +01006492/* does 3 actions :
6493 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6494 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6495 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6496 *
6497 * returns 0 if initialization failed, !0 otherwise.
6498 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006499
willy tarreauad90a0c2005-12-18 01:09:15 +01006500
willy tarreau1c2ad212005-12-18 01:11:29 +01006501int select_loop(int action) {
6502 int next_time;
6503 int status;
6504 int fd,i;
6505 struct timeval delta;
6506 int readnotnull, writenotnull;
6507 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01006508
willy tarreau1c2ad212005-12-18 01:11:29 +01006509 if (action == POLL_LOOP_ACTION_INIT) {
6510 ReadEvent = (fd_set *)
6511 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6512 WriteEvent = (fd_set *)
6513 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6514 return 1;
6515 }
6516 else if (action == POLL_LOOP_ACTION_CLEAN) {
6517 if (WriteEvent) free(WriteEvent);
6518 if (ReadEvent) free(ReadEvent);
6519 return 1;
6520 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006521
willy tarreau1c2ad212005-12-18 01:11:29 +01006522 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01006523
willy tarreau1c2ad212005-12-18 01:11:29 +01006524 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006525
willy tarreau1c2ad212005-12-18 01:11:29 +01006526 while (1) {
6527 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01006528
willy tarreau1c2ad212005-12-18 01:11:29 +01006529 /* stop when there's no connection left and we don't allow them anymore */
6530 if (!actconn && listeners == 0)
6531 break;
6532
6533#if STATTIME > 0
6534 {
6535 int time2;
6536 time2 = stats();
6537 next_time = MINTIME(time2, next_time);
6538 }
6539#endif
6540
willy tarreau1c2ad212005-12-18 01:11:29 +01006541 if (next_time > 0) { /* FIXME */
6542 /* Convert to timeval */
6543 /* to avoid eventual select loops due to timer precision */
6544 next_time += SCHEDULER_RESOLUTION;
6545 delta.tv_sec = next_time / 1000;
6546 delta.tv_usec = (next_time % 1000) * 1000;
6547 }
6548 else if (next_time == 0) { /* allow select to return immediately when needed */
6549 delta.tv_sec = delta.tv_usec = 0;
6550 }
6551
6552
6553 /* let's restore fdset state */
6554
6555 readnotnull = 0; writenotnull = 0;
6556 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
6557 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
6558 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
6559 }
6560
6561 // /* just a verification code, needs to be removed for performance */
6562 // for (i=0; i<maxfd; i++) {
6563 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
6564 // abort();
6565 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
6566 // abort();
6567 //
6568 // }
6569
6570 status = select(maxfd,
6571 readnotnull ? ReadEvent : NULL,
6572 writenotnull ? WriteEvent : NULL,
6573 NULL,
6574 (next_time >= 0) ? &delta : NULL);
6575
6576 /* this is an experiment on the separation of the select work */
6577 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6578 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6579
6580 tv_now(&now);
6581
6582 if (status > 0) { /* must proceed with events */
6583
6584 int fds;
6585 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01006586
willy tarreau1c2ad212005-12-18 01:11:29 +01006587 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
6588 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
6589 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
6590
6591 /* if we specify read first, the accepts and zero reads will be
6592 * seen first. Moreover, system buffers will be flushed faster.
6593 */
willy tarreau05be12b2006-03-19 19:35:00 +01006594 if (FD_ISSET(fd, ReadEvent)) {
6595 if (fdtab[fd].state == FD_STCLOSE)
6596 continue;
6597 fdtab[fd].read(fd);
6598 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006599
willy tarreau05be12b2006-03-19 19:35:00 +01006600 if (FD_ISSET(fd, WriteEvent)) {
6601 if (fdtab[fd].state == FD_STCLOSE)
6602 continue;
6603 fdtab[fd].write(fd);
6604 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006605 }
6606 }
6607 else {
6608 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01006609 }
willy tarreau0f7af912005-12-17 12:21:26 +01006610 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006611 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006612}
6613
6614
6615#if STATTIME > 0
6616/*
6617 * Display proxy statistics regularly. It is designed to be called from the
6618 * select_loop().
6619 */
6620int stats(void) {
6621 static int lines;
6622 static struct timeval nextevt;
6623 static struct timeval lastevt;
6624 static struct timeval starttime = {0,0};
6625 unsigned long totaltime, deltatime;
6626 int ret;
6627
willy tarreau750a4722005-12-17 13:21:24 +01006628 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01006629 deltatime = (tv_diff(&lastevt, &now)?:1);
6630 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01006631
willy tarreau9fe663a2005-12-17 13:02:59 +01006632 if (global.mode & MODE_STATS) {
6633 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006634 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01006635 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
6636 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006637 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01006638 actconn, totalconn,
6639 stats_tsk_new, stats_tsk_good,
6640 stats_tsk_left, stats_tsk_right,
6641 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
6642 }
6643 }
6644
6645 tv_delayfrom(&nextevt, &now, STATTIME);
6646
6647 lastevt=now;
6648 }
6649 ret = tv_remain(&now, &nextevt);
6650 return ret;
6651}
6652#endif
6653
6654
6655/*
6656 * this function enables proxies when there are enough free sessions,
6657 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01006658 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01006659 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01006660 */
6661static int maintain_proxies(void) {
6662 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01006663 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006664 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01006665
6666 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01006667 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01006668
6669 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01006670 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01006671 while (p) {
6672 if (p->nbconn < p->maxconn) {
6673 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006674 for (l = p->listen; l != NULL; l = l->next) {
6675 FD_SET(l->fd, StaticReadEvent);
6676 }
willy tarreau0f7af912005-12-17 12:21:26 +01006677 p->state = PR_STRUN;
6678 }
6679 }
6680 else {
6681 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006682 for (l = p->listen; l != NULL; l = l->next) {
6683 FD_CLR(l->fd, StaticReadEvent);
6684 }
willy tarreau0f7af912005-12-17 12:21:26 +01006685 p->state = PR_STIDLE;
6686 }
6687 }
6688 p = p->next;
6689 }
6690 }
6691 else { /* block all proxies */
6692 while (p) {
6693 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006694 for (l = p->listen; l != NULL; l = l->next) {
6695 FD_CLR(l->fd, StaticReadEvent);
6696 }
willy tarreau0f7af912005-12-17 12:21:26 +01006697 p->state = PR_STIDLE;
6698 }
6699 p = p->next;
6700 }
6701 }
6702
willy tarreau5cbea6f2005-12-17 12:48:26 +01006703 if (stopping) {
6704 p = proxy;
6705 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01006706 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006707 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006708 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006709 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006710 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006711 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006712
willy tarreaua41a8b42005-12-17 14:02:24 +01006713 for (l = p->listen; l != NULL; l = l->next) {
6714 fd_delete(l->fd);
6715 listeners--;
6716 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006717 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006718 }
6719 else {
6720 tleft = MINTIME(t, tleft);
6721 }
6722 }
6723 p = p->next;
6724 }
6725 }
6726 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006727}
6728
6729/*
6730 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006731 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6732 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006733 */
6734static void soft_stop(void) {
6735 struct proxy *p;
6736
6737 stopping = 1;
6738 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006739 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006740 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006741 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006742 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006743 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006744 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006745 }
willy tarreau0f7af912005-12-17 12:21:26 +01006746 p = p->next;
6747 }
6748}
6749
willy tarreaudbd3bef2006-01-20 19:35:18 +01006750static void pause_proxy(struct proxy *p) {
6751 struct listener *l;
6752 for (l = p->listen; l != NULL; l = l->next) {
6753 shutdown(l->fd, SHUT_RD);
6754 FD_CLR(l->fd, StaticReadEvent);
6755 p->state = PR_STPAUSED;
6756 }
6757}
6758
6759/*
6760 * This function temporarily disables listening so that another new instance
6761 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006762 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006763 * the proxy, or a SIGTTIN can be sent to listen again.
6764 */
6765static void pause_proxies(void) {
6766 struct proxy *p;
6767
6768 p = proxy;
6769 tv_now(&now); /* else, the old time before select will be used */
6770 while (p) {
6771 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6772 Warning("Pausing proxy %s.\n", p->id);
6773 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6774 pause_proxy(p);
6775 }
6776 p = p->next;
6777 }
6778}
6779
6780
6781/*
6782 * This function reactivates listening. This can be used after a call to
6783 * sig_pause(), for example when a new instance has failed starting up.
6784 * It is designed to be called upon reception of a SIGTTIN.
6785 */
6786static void listen_proxies(void) {
6787 struct proxy *p;
6788 struct listener *l;
6789
6790 p = proxy;
6791 tv_now(&now); /* else, the old time before select will be used */
6792 while (p) {
6793 if (p->state == PR_STPAUSED) {
6794 Warning("Enabling proxy %s.\n", p->id);
6795 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6796
6797 for (l = p->listen; l != NULL; l = l->next) {
6798 if (listen(l->fd, p->maxconn) == 0) {
6799 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6800 FD_SET(l->fd, StaticReadEvent);
6801 p->state = PR_STRUN;
6802 }
6803 else
6804 p->state = PR_STIDLE;
6805 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006806 int port;
6807
6808 if (l->addr.ss_family == AF_INET6)
6809 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6810 else
6811 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6812
willy tarreaudbd3bef2006-01-20 19:35:18 +01006813 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006814 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006815 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006816 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006817 /* Another port might have been enabled. Let's stop everything. */
6818 pause_proxy(p);
6819 break;
6820 }
6821 }
6822 }
6823 p = p->next;
6824 }
6825}
6826
6827
willy tarreau0f7af912005-12-17 12:21:26 +01006828/*
6829 * upon SIGUSR1, let's have a soft stop.
6830 */
6831void sig_soft_stop(int sig) {
6832 soft_stop();
6833 signal(sig, SIG_IGN);
6834}
6835
willy tarreaudbd3bef2006-01-20 19:35:18 +01006836/*
6837 * upon SIGTTOU, we pause everything
6838 */
6839void sig_pause(int sig) {
6840 pause_proxies();
6841 signal(sig, sig_pause);
6842}
willy tarreau0f7af912005-12-17 12:21:26 +01006843
willy tarreau8337c6b2005-12-17 13:41:01 +01006844/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006845 * upon SIGTTIN, let's have a soft stop.
6846 */
6847void sig_listen(int sig) {
6848 listen_proxies();
6849 signal(sig, sig_listen);
6850}
6851
6852/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006853 * this function dumps every server's state when the process receives SIGHUP.
6854 */
6855void sig_dump_state(int sig) {
6856 struct proxy *p = proxy;
6857
6858 Warning("SIGHUP received, dumping servers states.\n");
6859 while (p) {
6860 struct server *s = p->srv;
6861
willy tarreau4632c212006-05-02 23:32:51 +02006862 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006863 while (s) {
willy tarreau4632c212006-05-02 23:32:51 +02006864 snprintf(trash, sizeof(trash),
6865 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %d tot.",
6866 p->id, s->id,
6867 (s->state & SRV_RUNNING) ? "UP" : "DOWN",
6868 s->cur_sess, s->nbpend, s->cum_sess);
willy tarreau14b4d432006-04-07 18:23:29 +02006869 Warning("%s\n", trash);
6870 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01006871 s = s->next;
6872 }
willy tarreaudd07e972005-12-18 00:48:48 +01006873
willy tarreau62084d42006-03-24 18:57:41 +01006874 if (p->srv_act == 0) {
willy tarreau4632c212006-05-02 23:32:51 +02006875 snprintf(trash, sizeof(trash),
6876 "SIGHUP: Proxy %s %s ! Conn: %d act, %d pend (%d unass), %d tot.",
6877 p->id,
6878 (p->srv_bck) ? "is running on backup servers" : "has no server available",
6879 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02006880 } else {
6881 snprintf(trash, sizeof(trash),
willy tarreau4632c212006-05-02 23:32:51 +02006882 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
6883 " Conn: %d act, %d pend (%d unass), %d tot.",
6884 p->id, p->srv_act, p->srv_bck,
6885 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02006886 }
6887 Warning("%s\n", trash);
6888 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01006889
willy tarreau8337c6b2005-12-17 13:41:01 +01006890 p = p->next;
6891 }
6892 signal(sig, sig_dump_state);
6893}
6894
willy tarreau0f7af912005-12-17 12:21:26 +01006895void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006896 struct task *t, *tnext;
6897 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006898
willy tarreau5e698ef2006-05-02 14:51:00 +02006899 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6900 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006901 tnext = t->next;
6902 s = t->context;
6903 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6904 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6905 "req=%d, rep=%d, clifd=%d\n",
6906 s, tv_remain(&now, &t->expire),
6907 s->cli_state,
6908 s->srv_state,
6909 FD_ISSET(s->cli_fd, StaticReadEvent),
6910 FD_ISSET(s->cli_fd, StaticWriteEvent),
6911 FD_ISSET(s->srv_fd, StaticReadEvent),
6912 FD_ISSET(s->srv_fd, StaticWriteEvent),
6913 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6914 );
willy tarreau0f7af912005-12-17 12:21:26 +01006915 }
willy tarreau12350152005-12-18 01:03:27 +01006916}
6917
willy tarreau64a3cc32005-12-18 01:13:11 +01006918#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006919static void fast_stop(void)
6920{
6921 struct proxy *p;
6922 p = proxy;
6923 while (p) {
6924 p->grace = 0;
6925 p = p->next;
6926 }
6927 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006928}
6929
willy tarreau12350152005-12-18 01:03:27 +01006930void sig_int(int sig) {
6931 /* This would normally be a hard stop,
6932 but we want to be sure about deallocation,
6933 and so on, so we do a soft stop with
6934 0 GRACE time
6935 */
6936 fast_stop();
6937 /* If we are killed twice, we decide to die*/
6938 signal(sig, SIG_DFL);
6939}
6940
6941void sig_term(int sig) {
6942 /* This would normally be a hard stop,
6943 but we want to be sure about deallocation,
6944 and so on, so we do a soft stop with
6945 0 GRACE time
6946 */
6947 fast_stop();
6948 /* If we are killed twice, we decide to die*/
6949 signal(sig, SIG_DFL);
6950}
willy tarreau64a3cc32005-12-18 01:13:11 +01006951#endif
willy tarreau12350152005-12-18 01:03:27 +01006952
willy tarreauc1f47532005-12-18 01:08:26 +01006953/* returns the pointer to an error in the replacement string, or NULL if OK */
6954char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006955 struct hdr_exp *exp;
6956
willy tarreauc1f47532005-12-18 01:08:26 +01006957 if (replace != NULL) {
6958 char *err;
6959 err = check_replace_string(replace);
6960 if (err)
6961 return err;
6962 }
6963
willy tarreaue39cd132005-12-17 13:00:18 +01006964 while (*head != NULL)
6965 head = &(*head)->next;
6966
6967 exp = calloc(1, sizeof(struct hdr_exp));
6968
6969 exp->preg = preg;
6970 exp->replace = replace;
6971 exp->action = action;
6972 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006973
6974 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006975}
6976
willy tarreau9fe663a2005-12-17 13:02:59 +01006977
willy tarreau0f7af912005-12-17 12:21:26 +01006978/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006979 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006980 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006981int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006982
willy tarreau9fe663a2005-12-17 13:02:59 +01006983 if (!strcmp(args[0], "global")) { /* new section */
6984 /* no option, nothing special to do */
6985 return 0;
6986 }
6987 else if (!strcmp(args[0], "daemon")) {
6988 global.mode |= MODE_DAEMON;
6989 }
6990 else if (!strcmp(args[0], "debug")) {
6991 global.mode |= MODE_DEBUG;
6992 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006993 else if (!strcmp(args[0], "noepoll")) {
6994 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6995 }
6996 else if (!strcmp(args[0], "nopoll")) {
6997 cfg_polling_mechanism &= ~POLL_USE_POLL;
6998 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006999 else if (!strcmp(args[0], "quiet")) {
7000 global.mode |= MODE_QUIET;
7001 }
7002 else if (!strcmp(args[0], "stats")) {
7003 global.mode |= MODE_STATS;
7004 }
7005 else if (!strcmp(args[0], "uid")) {
7006 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007007 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007008 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007009 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007010 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007011 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007012 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007013 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007014 global.uid = atol(args[1]);
7015 }
7016 else if (!strcmp(args[0], "gid")) {
7017 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007018 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007019 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007020 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007021 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007022 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007023 return -1;
7024 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007025 global.gid = atol(args[1]);
7026 }
7027 else if (!strcmp(args[0], "nbproc")) {
7028 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007029 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007030 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007031 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007032 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007033 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007034 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007035 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007036 global.nbproc = atol(args[1]);
7037 }
7038 else if (!strcmp(args[0], "maxconn")) {
7039 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007040 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007041 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007042 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007043 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007044 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007045 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007046 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007047 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01007048#ifdef SYSTEM_MAXCONN
7049 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
7050 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);
7051 global.maxconn = DEFAULT_MAXCONN;
7052 }
7053#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01007054 }
willy tarreaub1285d52005-12-18 01:20:14 +01007055 else if (!strcmp(args[0], "ulimit-n")) {
7056 if (global.rlimit_nofile != 0) {
7057 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7058 return 0;
7059 }
7060 if (*(args[1]) == 0) {
7061 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
7062 return -1;
7063 }
7064 global.rlimit_nofile = atol(args[1]);
7065 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007066 else if (!strcmp(args[0], "chroot")) {
7067 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007068 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007069 return 0;
7070 }
7071 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007072 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007073 return -1;
7074 }
7075 global.chroot = strdup(args[1]);
7076 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007077 else if (!strcmp(args[0], "pidfile")) {
7078 if (global.pidfile != NULL) {
7079 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7080 return 0;
7081 }
7082 if (*(args[1]) == 0) {
7083 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
7084 return -1;
7085 }
7086 global.pidfile = strdup(args[1]);
7087 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007088 else if (!strcmp(args[0], "log")) { /* syslog server address */
7089 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01007090 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007091
7092 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007093 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007094 return -1;
7095 }
7096
7097 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7098 if (!strcmp(log_facilities[facility], args[2]))
7099 break;
7100
7101 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007102 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007103 exit(1);
7104 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007105
7106 level = 7; /* max syslog level = debug */
7107 if (*(args[3])) {
7108 while (level >= 0 && strcmp(log_levels[level], args[3]))
7109 level--;
7110 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007111 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007112 exit(1);
7113 }
7114 }
7115
willy tarreau9fe663a2005-12-17 13:02:59 +01007116 sa = str2sa(args[1]);
7117 if (!sa->sin_port)
7118 sa->sin_port = htons(SYSLOG_PORT);
7119
7120 if (global.logfac1 == -1) {
7121 global.logsrv1 = *sa;
7122 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007123 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007124 }
7125 else if (global.logfac2 == -1) {
7126 global.logsrv2 = *sa;
7127 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007128 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007129 }
7130 else {
7131 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
7132 return -1;
7133 }
7134
7135 }
7136 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007137 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01007138 return -1;
7139 }
7140 return 0;
7141}
7142
7143
willy tarreaua41a8b42005-12-17 14:02:24 +01007144void init_default_instance() {
7145 memset(&defproxy, 0, sizeof(defproxy));
7146 defproxy.mode = PR_MODE_TCP;
7147 defproxy.state = PR_STNEW;
7148 defproxy.maxconn = cfg_maxpconn;
7149 defproxy.conn_retries = CONN_RETRIES;
7150 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
7151}
7152
willy tarreau9fe663a2005-12-17 13:02:59 +01007153/*
7154 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
7155 */
7156int cfg_parse_listen(char *file, int linenum, char **args) {
7157 static struct proxy *curproxy = NULL;
7158 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01007159 char *err;
willy tarreau12350152005-12-18 01:03:27 +01007160 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01007161
7162 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01007163 if (!*args[1]) {
7164 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
7165 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007166 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007167 return -1;
7168 }
7169
7170 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007171 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007172 return -1;
7173 }
willy tarreaudfece232006-05-02 00:19:57 +02007174
willy tarreau9fe663a2005-12-17 13:02:59 +01007175 curproxy->next = proxy;
7176 proxy = curproxy;
willy tarreaudfece232006-05-02 00:19:57 +02007177 LIST_INIT(&curproxy->pendconns);
7178
willy tarreau9fe663a2005-12-17 13:02:59 +01007179 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01007180
7181 /* parse the listener address if any */
7182 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007183 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007184 if (!curproxy->listen)
7185 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007186 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01007187 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007188
willy tarreau9fe663a2005-12-17 13:02:59 +01007189 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01007190 curproxy->state = defproxy.state;
7191 curproxy->maxconn = defproxy.maxconn;
7192 curproxy->conn_retries = defproxy.conn_retries;
7193 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007194
7195 if (defproxy.check_req)
7196 curproxy->check_req = strdup(defproxy.check_req);
7197 curproxy->check_len = defproxy.check_len;
7198
7199 if (defproxy.cookie_name)
7200 curproxy->cookie_name = strdup(defproxy.cookie_name);
7201 curproxy->cookie_len = defproxy.cookie_len;
7202
7203 if (defproxy.capture_name)
7204 curproxy->capture_name = strdup(defproxy.capture_name);
7205 curproxy->capture_namelen = defproxy.capture_namelen;
7206 curproxy->capture_len = defproxy.capture_len;
7207
7208 if (defproxy.errmsg.msg400)
7209 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
7210 curproxy->errmsg.len400 = defproxy.errmsg.len400;
7211
7212 if (defproxy.errmsg.msg403)
7213 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
7214 curproxy->errmsg.len403 = defproxy.errmsg.len403;
7215
7216 if (defproxy.errmsg.msg408)
7217 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
7218 curproxy->errmsg.len408 = defproxy.errmsg.len408;
7219
7220 if (defproxy.errmsg.msg500)
7221 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
7222 curproxy->errmsg.len500 = defproxy.errmsg.len500;
7223
7224 if (defproxy.errmsg.msg502)
7225 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
7226 curproxy->errmsg.len502 = defproxy.errmsg.len502;
7227
7228 if (defproxy.errmsg.msg503)
7229 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
7230 curproxy->errmsg.len503 = defproxy.errmsg.len503;
7231
7232 if (defproxy.errmsg.msg504)
7233 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
7234 curproxy->errmsg.len504 = defproxy.errmsg.len504;
7235
willy tarreaua41a8b42005-12-17 14:02:24 +01007236 curproxy->clitimeout = defproxy.clitimeout;
7237 curproxy->contimeout = defproxy.contimeout;
7238 curproxy->srvtimeout = defproxy.srvtimeout;
7239 curproxy->mode = defproxy.mode;
7240 curproxy->logfac1 = defproxy.logfac1;
7241 curproxy->logsrv1 = defproxy.logsrv1;
7242 curproxy->loglev1 = defproxy.loglev1;
7243 curproxy->logfac2 = defproxy.logfac2;
7244 curproxy->logsrv2 = defproxy.logsrv2;
7245 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01007246 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01007247 curproxy->grace = defproxy.grace;
7248 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01007249 curproxy->mon_net = defproxy.mon_net;
7250 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01007251 return 0;
7252 }
7253 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007254 /* some variables may have already been initialized earlier */
7255 if (defproxy.check_req) free(defproxy.check_req);
7256 if (defproxy.cookie_name) free(defproxy.cookie_name);
7257 if (defproxy.capture_name) free(defproxy.capture_name);
7258 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
7259 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
7260 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
7261 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
7262 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
7263 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
7264 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
7265
7266 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01007267 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01007268 return 0;
7269 }
7270 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007271 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007272 return -1;
7273 }
7274
willy tarreaua41a8b42005-12-17 14:02:24 +01007275 if (!strcmp(args[0], "bind")) { /* new listen addresses */
7276 if (curproxy == &defproxy) {
7277 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7278 return -1;
7279 }
7280
7281 if (strchr(args[1], ':') == NULL) {
7282 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
7283 file, linenum, args[0]);
7284 return -1;
7285 }
7286 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007287 if (!curproxy->listen)
7288 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007289 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007290 return 0;
7291 }
willy tarreaub1285d52005-12-18 01:20:14 +01007292 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
7293 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
7294 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
7295 file, linenum, args[0]);
7296 return -1;
7297 }
7298 /* flush useless bits */
7299 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
7300 return 0;
7301 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007302 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01007303 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
7304 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
7305 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
7306 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007307 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007308 return -1;
7309 }
7310 }
7311 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01007312 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007313 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007314 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
7315 curproxy->state = PR_STNEW;
7316 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007317 else if (!strcmp(args[0], "cookie")) { /* cookie name */
7318 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007319// if (curproxy == &defproxy) {
7320// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7321// return -1;
7322// }
willy tarreaua41a8b42005-12-17 14:02:24 +01007323
willy tarreau9fe663a2005-12-17 13:02:59 +01007324 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007325// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7326// file, linenum);
7327// return 0;
7328 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007329 }
7330
7331 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007332 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
7333 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007334 return -1;
7335 }
7336 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007337 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007338
7339 cur_arg = 2;
7340 while (*(args[cur_arg])) {
7341 if (!strcmp(args[cur_arg], "rewrite")) {
7342 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01007343 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007344 else if (!strcmp(args[cur_arg], "indirect")) {
7345 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01007346 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007347 else if (!strcmp(args[cur_arg], "insert")) {
7348 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01007349 }
willy tarreau240afa62005-12-17 13:14:35 +01007350 else if (!strcmp(args[cur_arg], "nocache")) {
7351 curproxy->options |= PR_O_COOK_NOC;
7352 }
willy tarreaucd878942005-12-17 13:27:43 +01007353 else if (!strcmp(args[cur_arg], "postonly")) {
7354 curproxy->options |= PR_O_COOK_POST;
7355 }
willy tarreau0174f312005-12-18 01:02:42 +01007356 else if (!strcmp(args[cur_arg], "prefix")) {
7357 curproxy->options |= PR_O_COOK_PFX;
7358 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007359 else {
willy tarreau0174f312005-12-18 01:02:42 +01007360 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007361 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007362 return -1;
7363 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007364 cur_arg++;
7365 }
willy tarreau0174f312005-12-18 01:02:42 +01007366 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
7367 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
7368 file, linenum);
7369 return -1;
7370 }
7371
7372 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
7373 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007374 file, linenum);
7375 return -1;
7376 }
willy tarreau12350152005-12-18 01:03:27 +01007377 }/* end else if (!strcmp(args[0], "cookie")) */
7378 else if (!strcmp(args[0], "appsession")) { /* cookie name */
7379// if (curproxy == &defproxy) {
7380// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7381// return -1;
7382// }
7383
7384 if (curproxy->appsession_name != NULL) {
7385// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7386// file, linenum);
7387// return 0;
7388 free(curproxy->appsession_name);
7389 }
7390
7391 if (*(args[5]) == 0) {
7392 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
7393 file, linenum, args[0]);
7394 return -1;
7395 }
7396 have_appsession = 1;
7397 curproxy->appsession_name = strdup(args[1]);
7398 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
7399 curproxy->appsession_len = atoi(args[3]);
7400 curproxy->appsession_timeout = atoi(args[5]);
7401 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
7402 if (rc) {
7403 Alert("Error Init Appsession Hashtable.\n");
7404 return -1;
7405 }
7406 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01007407 else if (!strcmp(args[0], "capture")) {
7408 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
7409 // if (curproxy == &defproxy) {
7410 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7411 // return -1;
7412 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007413
willy tarreau4302f492005-12-18 01:00:37 +01007414 if (curproxy->capture_name != NULL) {
7415 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7416 // file, linenum, args[0]);
7417 // return 0;
7418 free(curproxy->capture_name);
7419 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007420
willy tarreau4302f492005-12-18 01:00:37 +01007421 if (*(args[4]) == 0) {
7422 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
7423 file, linenum, args[0]);
7424 return -1;
7425 }
7426 curproxy->capture_name = strdup(args[2]);
7427 curproxy->capture_namelen = strlen(curproxy->capture_name);
7428 curproxy->capture_len = atol(args[4]);
7429 if (curproxy->capture_len >= CAPTURE_LEN) {
7430 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
7431 file, linenum, CAPTURE_LEN - 1);
7432 curproxy->capture_len = CAPTURE_LEN - 1;
7433 }
7434 curproxy->to_log |= LW_COOKIE;
7435 }
7436 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
7437 struct cap_hdr *hdr;
7438
7439 if (curproxy == &defproxy) {
7440 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7441 return -1;
7442 }
7443
7444 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7445 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7446 file, linenum, args[0], args[1]);
7447 return -1;
7448 }
7449
7450 hdr = calloc(sizeof(struct cap_hdr), 1);
7451 hdr->next = curproxy->req_cap;
7452 hdr->name = strdup(args[3]);
7453 hdr->namelen = strlen(args[3]);
7454 hdr->len = atol(args[5]);
7455 hdr->index = curproxy->nb_req_cap++;
7456 curproxy->req_cap = hdr;
7457 curproxy->to_log |= LW_REQHDR;
7458 }
7459 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
7460 struct cap_hdr *hdr;
7461
7462 if (curproxy == &defproxy) {
7463 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7464 return -1;
7465 }
7466
7467 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7468 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7469 file, linenum, args[0], args[1]);
7470 return -1;
7471 }
7472 hdr = calloc(sizeof(struct cap_hdr), 1);
7473 hdr->next = curproxy->rsp_cap;
7474 hdr->name = strdup(args[3]);
7475 hdr->namelen = strlen(args[3]);
7476 hdr->len = atol(args[5]);
7477 hdr->index = curproxy->nb_rsp_cap++;
7478 curproxy->rsp_cap = hdr;
7479 curproxy->to_log |= LW_RSPHDR;
7480 }
7481 else {
7482 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007483 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007484 return -1;
7485 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007486 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007487 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007488 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007489 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007490 return 0;
7491 }
7492 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007493 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7494 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007495 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007496 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007497 curproxy->contimeout = atol(args[1]);
7498 }
7499 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007500 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007501 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7502 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007503 return 0;
7504 }
7505 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007506 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7507 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007508 return -1;
7509 }
7510 curproxy->clitimeout = atol(args[1]);
7511 }
7512 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007513 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007514 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007515 return 0;
7516 }
7517 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007518 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7519 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007520 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007521 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007522 curproxy->srvtimeout = atol(args[1]);
7523 }
7524 else if (!strcmp(args[0], "retries")) { /* connection retries */
7525 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007526 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
7527 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007528 return -1;
7529 }
7530 curproxy->conn_retries = atol(args[1]);
7531 }
7532 else if (!strcmp(args[0], "option")) {
7533 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007534 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007535 return -1;
7536 }
7537 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007538 /* enable reconnections to dispatch */
7539 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01007540#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007541 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007542 /* enable transparent proxy connections */
7543 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01007544#endif
7545 else if (!strcmp(args[1], "keepalive"))
7546 /* enable keep-alive */
7547 curproxy->options |= PR_O_KEEPALIVE;
7548 else if (!strcmp(args[1], "forwardfor"))
7549 /* insert x-forwarded-for field */
7550 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01007551 else if (!strcmp(args[1], "logasap"))
7552 /* log as soon as possible, without waiting for the session to complete */
7553 curproxy->options |= PR_O_LOGASAP;
7554 else if (!strcmp(args[1], "httpclose"))
7555 /* force connection: close in both directions in HTTP mode */
7556 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01007557 else if (!strcmp(args[1], "forceclose"))
7558 /* force connection: close in both directions in HTTP mode and enforce end of session */
7559 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01007560 else if (!strcmp(args[1], "checkcache"))
7561 /* require examination of cacheability of the 'set-cookie' field */
7562 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01007563 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01007564 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007565 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01007566 else if (!strcmp(args[1], "tcplog"))
7567 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007568 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01007569 else if (!strcmp(args[1], "dontlognull")) {
7570 /* don't log empty requests */
7571 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007572 }
willy tarreaub952e1d2005-12-18 01:31:20 +01007573 else if (!strcmp(args[1], "tcpka")) {
7574 /* enable TCP keep-alives on client and server sessions */
7575 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
7576 }
7577 else if (!strcmp(args[1], "clitcpka")) {
7578 /* enable TCP keep-alives on client sessions */
7579 curproxy->options |= PR_O_TCP_CLI_KA;
7580 }
7581 else if (!strcmp(args[1], "srvtcpka")) {
7582 /* enable TCP keep-alives on server sessions */
7583 curproxy->options |= PR_O_TCP_SRV_KA;
7584 }
Willy TARREAU3481c462006-03-01 22:37:57 +01007585 else if (!strcmp(args[1], "allbackups")) {
7586 /* Use all backup servers simultaneously */
7587 curproxy->options |= PR_O_USE_ALL_BK;
7588 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007589 else if (!strcmp(args[1], "httpchk")) {
7590 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007591 if (curproxy->check_req != NULL) {
7592 free(curproxy->check_req);
7593 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007594 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007595 if (!*args[2]) { /* no argument */
7596 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
7597 curproxy->check_len = strlen(DEF_CHECK_REQ);
7598 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01007599 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
7600 curproxy->check_req = (char *)malloc(reqlen);
7601 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7602 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007603 } else { /* more arguments : METHOD URI [HTTP_VER] */
7604 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
7605 if (*args[4])
7606 reqlen += strlen(args[4]);
7607 else
7608 reqlen += strlen("HTTP/1.0");
7609
7610 curproxy->check_req = (char *)malloc(reqlen);
7611 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7612 "%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 +01007613 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007614 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007615 else if (!strcmp(args[1], "persist")) {
7616 /* persist on using the server specified by the cookie, even when it's down */
7617 curproxy->options |= PR_O_PERSIST;
7618 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007619 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007620 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007621 return -1;
7622 }
7623 return 0;
7624 }
7625 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
7626 /* enable reconnections to dispatch */
7627 curproxy->options |= PR_O_REDISP;
7628 }
willy tarreaua1598082005-12-17 13:08:06 +01007629#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007630 else if (!strcmp(args[0], "transparent")) {
7631 /* enable transparent proxy connections */
7632 curproxy->options |= PR_O_TRANSP;
7633 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007634#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01007635 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
7636 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007637 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007638 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007639 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007640 curproxy->maxconn = atol(args[1]);
7641 }
7642 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
7643 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007644 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007645 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007646 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007647 curproxy->grace = atol(args[1]);
7648 }
7649 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01007650 if (curproxy == &defproxy) {
7651 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7652 return -1;
7653 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007654 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007655 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007656 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007657 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007658 curproxy->dispatch_addr = *str2sa(args[1]);
7659 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007660 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01007661 if (*(args[1])) {
7662 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007663 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01007664 }
willy tarreau1a3442d2006-03-24 21:03:20 +01007665 else if (!strcmp(args[1], "source")) {
7666 curproxy->options |= PR_O_BALANCE_SH;
7667 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007668 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01007669 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007670 return -1;
7671 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007672 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007673 else /* if no option is set, use round-robin by default */
7674 curproxy->options |= PR_O_BALANCE_RR;
7675 }
7676 else if (!strcmp(args[0], "server")) { /* server address */
7677 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007678 char *rport;
7679 char *raddr;
7680 short realport;
7681 int do_check;
7682
7683 if (curproxy == &defproxy) {
7684 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7685 return -1;
7686 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007687
willy tarreaua41a8b42005-12-17 14:02:24 +01007688 if (!*args[2]) {
7689 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007690 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007691 return -1;
7692 }
7693 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
7694 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7695 return -1;
7696 }
willy tarreau0174f312005-12-18 01:02:42 +01007697
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007698 /* the servers are linked backwards first */
7699 newsrv->next = curproxy->srv;
7700 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01007701 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007702
willy tarreau18a957c2006-04-12 19:26:23 +02007703 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01007704 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01007705 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01007706 newsrv->id = strdup(args[1]);
7707
7708 /* several ways to check the port component :
7709 * - IP => port=+0, relative
7710 * - IP: => port=+0, relative
7711 * - IP:N => port=N, absolute
7712 * - IP:+N => port=+N, relative
7713 * - IP:-N => port=-N, relative
7714 */
7715 raddr = strdup(args[2]);
7716 rport = strchr(raddr, ':');
7717 if (rport) {
7718 *rport++ = 0;
7719 realport = atol(rport);
7720 if (!isdigit((int)*rport))
7721 newsrv->state |= SRV_MAPPORTS;
7722 } else {
7723 realport = 0;
7724 newsrv->state |= SRV_MAPPORTS;
7725 }
7726
7727 newsrv->addr = *str2sa(raddr);
7728 newsrv->addr.sin_port = htons(realport);
7729 free(raddr);
7730
willy tarreau9fe663a2005-12-17 13:02:59 +01007731 newsrv->curfd = -1; /* no health-check in progress */
7732 newsrv->inter = DEF_CHKINTR;
7733 newsrv->rise = DEF_RISETIME;
7734 newsrv->fall = DEF_FALLTIME;
7735 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7736 cur_arg = 3;
7737 while (*args[cur_arg]) {
7738 if (!strcmp(args[cur_arg], "cookie")) {
7739 newsrv->cookie = strdup(args[cur_arg + 1]);
7740 newsrv->cklen = strlen(args[cur_arg + 1]);
7741 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007742 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007743 else if (!strcmp(args[cur_arg], "rise")) {
7744 newsrv->rise = atol(args[cur_arg + 1]);
7745 newsrv->health = newsrv->rise;
7746 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007747 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007748 else if (!strcmp(args[cur_arg], "fall")) {
7749 newsrv->fall = atol(args[cur_arg + 1]);
7750 cur_arg += 2;
7751 }
7752 else if (!strcmp(args[cur_arg], "inter")) {
7753 newsrv->inter = atol(args[cur_arg + 1]);
7754 cur_arg += 2;
7755 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007756 else if (!strcmp(args[cur_arg], "port")) {
7757 newsrv->check_port = atol(args[cur_arg + 1]);
7758 cur_arg += 2;
7759 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007760 else if (!strcmp(args[cur_arg], "backup")) {
7761 newsrv->state |= SRV_BACKUP;
7762 cur_arg ++;
7763 }
willy tarreaue3f023f2006-04-08 21:52:24 +02007764 else if (!strcmp(args[cur_arg], "weight")) {
7765 int w;
7766 w = atol(args[cur_arg + 1]);
7767 if (w < 1 || w > 256) {
7768 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
7769 file, linenum, newsrv->id, w);
7770 return -1;
7771 }
7772 newsrv->uweight = w - 1;
7773 cur_arg += 2;
7774 }
willy tarreau18a957c2006-04-12 19:26:23 +02007775 else if (!strcmp(args[cur_arg], "maxconn")) {
7776 newsrv->maxconn = atol(args[cur_arg + 1]);
7777 cur_arg += 2;
7778 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007779 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007780 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007781 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007782 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007783 }
willy tarreau0174f312005-12-18 01:02:42 +01007784 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7785 if (!*args[cur_arg + 1]) {
7786 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7787 file, linenum, "source");
7788 return -1;
7789 }
7790 newsrv->state |= SRV_BIND_SRC;
7791 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7792 cur_arg += 2;
7793 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007794 else {
willy tarreaue3f023f2006-04-08 21:52:24 +02007795 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 +01007796 file, linenum, newsrv->id);
7797 return -1;
7798 }
7799 }
7800
7801 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007802 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7803 newsrv->check_port = realport; /* by default */
7804 if (!newsrv->check_port) {
7805 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 +01007806 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007807 return -1;
7808 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007809 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007810 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007811
willy tarreau62084d42006-03-24 18:57:41 +01007812 if (newsrv->state & SRV_BACKUP)
7813 curproxy->srv_bck++;
7814 else
7815 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007816 }
7817 else if (!strcmp(args[0], "log")) { /* syslog server address */
7818 struct sockaddr_in *sa;
7819 int facility;
7820
7821 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7822 curproxy->logfac1 = global.logfac1;
7823 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007824 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007825 curproxy->logfac2 = global.logfac2;
7826 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007827 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007828 }
7829 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007830 int level;
7831
willy tarreau0f7af912005-12-17 12:21:26 +01007832 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7833 if (!strcmp(log_facilities[facility], args[2]))
7834 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007835
willy tarreau0f7af912005-12-17 12:21:26 +01007836 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007837 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007838 exit(1);
7839 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007840
willy tarreau8337c6b2005-12-17 13:41:01 +01007841 level = 7; /* max syslog level = debug */
7842 if (*(args[3])) {
7843 while (level >= 0 && strcmp(log_levels[level], args[3]))
7844 level--;
7845 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007846 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007847 exit(1);
7848 }
7849 }
7850
willy tarreau0f7af912005-12-17 12:21:26 +01007851 sa = str2sa(args[1]);
7852 if (!sa->sin_port)
7853 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007854
willy tarreau0f7af912005-12-17 12:21:26 +01007855 if (curproxy->logfac1 == -1) {
7856 curproxy->logsrv1 = *sa;
7857 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007858 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007859 }
7860 else if (curproxy->logfac2 == -1) {
7861 curproxy->logsrv2 = *sa;
7862 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007863 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007864 }
7865 else {
7866 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007867 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007868 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007869 }
7870 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007871 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007872 file, linenum);
7873 return -1;
7874 }
7875 }
willy tarreaua1598082005-12-17 13:08:06 +01007876 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007877 if (!*args[1]) {
7878 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007879 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007880 return -1;
7881 }
7882
7883 curproxy->source_addr = *str2sa(args[1]);
7884 curproxy->options |= PR_O_BIND_SRC;
7885 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007886 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7887 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007888 if (curproxy == &defproxy) {
7889 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7890 return -1;
7891 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007892
7893 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007894 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7895 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007896 return -1;
7897 }
7898
7899 preg = calloc(1, sizeof(regex_t));
7900 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007901 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007902 return -1;
7903 }
7904
willy tarreauc1f47532005-12-18 01:08:26 +01007905 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7906 if (err) {
7907 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7908 file, linenum, *err);
7909 return -1;
7910 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007911 }
7912 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7913 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007914 if (curproxy == &defproxy) {
7915 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7916 return -1;
7917 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007918
7919 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007920 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007921 return -1;
7922 }
7923
7924 preg = calloc(1, sizeof(regex_t));
7925 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007926 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007927 return -1;
7928 }
7929
7930 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7931 }
7932 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7933 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007934 if (curproxy == &defproxy) {
7935 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7936 return -1;
7937 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007938
7939 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007940 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007941 return -1;
7942 }
7943
7944 preg = calloc(1, sizeof(regex_t));
7945 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007946 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007947 return -1;
7948 }
7949
7950 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7951 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007952 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7953 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007954 if (curproxy == &defproxy) {
7955 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7956 return -1;
7957 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007958
7959 if (*(args[1]) == 0) {
7960 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7961 return -1;
7962 }
7963
7964 preg = calloc(1, sizeof(regex_t));
7965 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7966 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7967 return -1;
7968 }
7969
7970 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7971 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007972 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7973 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007974 if (curproxy == &defproxy) {
7975 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7976 return -1;
7977 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007978
7979 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007980 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007981 return -1;
7982 }
7983
7984 preg = calloc(1, sizeof(regex_t));
7985 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007986 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007987 return -1;
7988 }
7989
7990 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7991 }
7992 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7993 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007994 if (curproxy == &defproxy) {
7995 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7996 return -1;
7997 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007998
7999 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008000 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8001 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008002 return -1;
8003 }
8004
8005 preg = calloc(1, sizeof(regex_t));
8006 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008007 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008008 return -1;
8009 }
8010
willy tarreauc1f47532005-12-18 01:08:26 +01008011 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8012 if (err) {
8013 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8014 file, linenum, *err);
8015 return -1;
8016 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008017 }
8018 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
8019 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008020 if (curproxy == &defproxy) {
8021 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8022 return -1;
8023 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008024
8025 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008026 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008027 return -1;
8028 }
8029
8030 preg = calloc(1, sizeof(regex_t));
8031 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008032 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008033 return -1;
8034 }
8035
8036 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8037 }
8038 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
8039 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008040 if (curproxy == &defproxy) {
8041 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8042 return -1;
8043 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008044
8045 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008046 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008047 return -1;
8048 }
8049
8050 preg = calloc(1, sizeof(regex_t));
8051 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008052 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008053 return -1;
8054 }
8055
8056 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8057 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008058 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
8059 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008060 if (curproxy == &defproxy) {
8061 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8062 return -1;
8063 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008064
8065 if (*(args[1]) == 0) {
8066 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8067 return -1;
8068 }
8069
8070 preg = calloc(1, sizeof(regex_t));
8071 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8072 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8073 return -1;
8074 }
8075
8076 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8077 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008078 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
8079 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008080 if (curproxy == &defproxy) {
8081 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8082 return -1;
8083 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008084
8085 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008086 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008087 return -1;
8088 }
8089
8090 preg = calloc(1, sizeof(regex_t));
8091 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008092 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008093 return -1;
8094 }
8095
8096 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8097 }
8098 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008099 if (curproxy == &defproxy) {
8100 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8101 return -1;
8102 }
8103
willy tarreau9fe663a2005-12-17 13:02:59 +01008104 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008105 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008106 return 0;
8107 }
8108
8109 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008110 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008111 return -1;
8112 }
8113
willy tarreau4302f492005-12-18 01:00:37 +01008114 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
8115 }
8116 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
8117 regex_t *preg;
8118
8119 if (*(args[1]) == 0 || *(args[2]) == 0) {
8120 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8121 file, linenum, args[0]);
8122 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008123 }
willy tarreau4302f492005-12-18 01:00:37 +01008124
8125 preg = calloc(1, sizeof(regex_t));
8126 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8127 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8128 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008129 }
willy tarreau4302f492005-12-18 01:00:37 +01008130
willy tarreauc1f47532005-12-18 01:08:26 +01008131 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8132 if (err) {
8133 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8134 file, linenum, *err);
8135 return -1;
8136 }
willy tarreau4302f492005-12-18 01:00:37 +01008137 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008138 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
8139 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008140 if (curproxy == &defproxy) {
8141 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8142 return -1;
8143 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008144
8145 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008146 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008147 return -1;
8148 }
willy tarreaue39cd132005-12-17 13:00:18 +01008149
willy tarreau9fe663a2005-12-17 13:02:59 +01008150 preg = calloc(1, sizeof(regex_t));
8151 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008152 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008153 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008154 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008155
willy tarreauc1f47532005-12-18 01:08:26 +01008156 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8157 if (err) {
8158 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8159 file, linenum, *err);
8160 return -1;
8161 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008162 }
willy tarreau982249e2005-12-18 00:57:06 +01008163 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
8164 regex_t *preg;
8165 if (curproxy == &defproxy) {
8166 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8167 return -1;
8168 }
8169
8170 if (*(args[1]) == 0) {
8171 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8172 return -1;
8173 }
8174
8175 preg = calloc(1, sizeof(regex_t));
8176 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8177 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8178 return -1;
8179 }
8180
willy tarreauc1f47532005-12-18 01:08:26 +01008181 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8182 if (err) {
8183 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8184 file, linenum, *err);
8185 return -1;
8186 }
willy tarreau982249e2005-12-18 00:57:06 +01008187 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008188 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01008189 regex_t *preg;
8190 if (curproxy == &defproxy) {
8191 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8192 return -1;
8193 }
willy tarreaue39cd132005-12-17 13:00:18 +01008194
willy tarreaua41a8b42005-12-17 14:02:24 +01008195 if (*(args[1]) == 0 || *(args[2]) == 0) {
8196 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8197 file, linenum, args[0]);
8198 return -1;
8199 }
willy tarreaue39cd132005-12-17 13:00:18 +01008200
willy tarreaua41a8b42005-12-17 14:02:24 +01008201 preg = calloc(1, sizeof(regex_t));
8202 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8203 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8204 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008205 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008206
willy tarreauc1f47532005-12-18 01:08:26 +01008207 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8208 if (err) {
8209 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8210 file, linenum, *err);
8211 return -1;
8212 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008213 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008214 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
8215 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008216 if (curproxy == &defproxy) {
8217 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8218 return -1;
8219 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008220
8221 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008222 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008223 return -1;
8224 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008225
willy tarreau9fe663a2005-12-17 13:02:59 +01008226 preg = calloc(1, sizeof(regex_t));
8227 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008228 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008229 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008230 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008231
willy tarreauc1f47532005-12-18 01:08:26 +01008232 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8233 if (err) {
8234 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8235 file, linenum, *err);
8236 return -1;
8237 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008238 }
willy tarreau982249e2005-12-18 00:57:06 +01008239 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
8240 regex_t *preg;
8241 if (curproxy == &defproxy) {
8242 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8243 return -1;
8244 }
8245
8246 if (*(args[1]) == 0) {
8247 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8248 return -1;
8249 }
8250
8251 preg = calloc(1, sizeof(regex_t));
8252 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8253 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8254 return -1;
8255 }
8256
willy tarreauc1f47532005-12-18 01:08:26 +01008257 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8258 if (err) {
8259 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8260 file, linenum, *err);
8261 return -1;
8262 }
willy tarreau982249e2005-12-18 00:57:06 +01008263 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008264 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008265 if (curproxy == &defproxy) {
8266 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8267 return -1;
8268 }
8269
willy tarreau9fe663a2005-12-17 13:02:59 +01008270 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008271 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008272 return 0;
8273 }
8274
8275 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008276 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008277 return -1;
8278 }
8279
8280 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
8281 }
willy tarreauc1f47532005-12-18 01:08:26 +01008282 else if (!strcmp(args[0], "errorloc") ||
8283 !strcmp(args[0], "errorloc302") ||
8284 !strcmp(args[0], "errorloc303")) { /* error location */
8285 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008286 char *err;
8287
willy tarreaueedaa9f2005-12-17 14:08:03 +01008288 // if (curproxy == &defproxy) {
8289 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8290 // return -1;
8291 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01008292
willy tarreau8337c6b2005-12-17 13:41:01 +01008293 if (*(args[2]) == 0) {
8294 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
8295 return -1;
8296 }
8297
8298 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01008299 if (!strcmp(args[0], "errorloc303")) {
8300 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
8301 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
8302 } else {
8303 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
8304 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
8305 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008306
8307 if (errnum == 400) {
8308 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008309 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008310 free(curproxy->errmsg.msg400);
8311 }
8312 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008313 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008314 }
8315 else if (errnum == 403) {
8316 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008317 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008318 free(curproxy->errmsg.msg403);
8319 }
8320 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008321 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008322 }
8323 else if (errnum == 408) {
8324 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008325 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008326 free(curproxy->errmsg.msg408);
8327 }
8328 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008329 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008330 }
8331 else if (errnum == 500) {
8332 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008333 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008334 free(curproxy->errmsg.msg500);
8335 }
8336 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008337 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008338 }
8339 else if (errnum == 502) {
8340 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008341 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008342 free(curproxy->errmsg.msg502);
8343 }
8344 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008345 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008346 }
8347 else if (errnum == 503) {
8348 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008349 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008350 free(curproxy->errmsg.msg503);
8351 }
8352 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008353 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008354 }
8355 else if (errnum == 504) {
8356 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008357 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008358 free(curproxy->errmsg.msg504);
8359 }
8360 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008361 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008362 }
8363 else {
8364 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
8365 free(err);
8366 }
8367 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008368 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008369 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01008370 return -1;
8371 }
8372 return 0;
8373}
willy tarreaue39cd132005-12-17 13:00:18 +01008374
willy tarreau5cbea6f2005-12-17 12:48:26 +01008375
willy tarreau9fe663a2005-12-17 13:02:59 +01008376/*
8377 * This function reads and parses the configuration file given in the argument.
8378 * returns 0 if OK, -1 if error.
8379 */
8380int readcfgfile(char *file) {
8381 char thisline[256];
8382 char *line;
8383 FILE *f;
8384 int linenum = 0;
8385 char *end;
8386 char *args[MAX_LINE_ARGS];
8387 int arg;
8388 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01008389 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01008390 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01008391
willy tarreau9fe663a2005-12-17 13:02:59 +01008392 struct proxy *curproxy = NULL;
8393 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01008394
willy tarreau9fe663a2005-12-17 13:02:59 +01008395 if ((f=fopen(file,"r")) == NULL)
8396 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008397
willy tarreaueedaa9f2005-12-17 14:08:03 +01008398 init_default_instance();
8399
willy tarreau9fe663a2005-12-17 13:02:59 +01008400 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
8401 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008402
willy tarreau9fe663a2005-12-17 13:02:59 +01008403 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01008404
willy tarreau9fe663a2005-12-17 13:02:59 +01008405 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01008406 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01008407 line++;
8408
8409 arg = 0;
8410 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01008411
willy tarreau9fe663a2005-12-17 13:02:59 +01008412 while (*line && arg < MAX_LINE_ARGS) {
8413 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
8414 * C equivalent value. Other combinations left unchanged (eg: \1).
8415 */
8416 if (*line == '\\') {
8417 int skip = 0;
8418 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
8419 *line = line[1];
8420 skip = 1;
8421 }
8422 else if (line[1] == 'r') {
8423 *line = '\r';
8424 skip = 1;
8425 }
8426 else if (line[1] == 'n') {
8427 *line = '\n';
8428 skip = 1;
8429 }
8430 else if (line[1] == 't') {
8431 *line = '\t';
8432 skip = 1;
8433 }
willy tarreauc1f47532005-12-18 01:08:26 +01008434 else if (line[1] == 'x') {
8435 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
8436 unsigned char hex1, hex2;
8437 hex1 = toupper(line[2]) - '0';
8438 hex2 = toupper(line[3]) - '0';
8439 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
8440 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
8441 *line = (hex1<<4) + hex2;
8442 skip = 3;
8443 }
8444 else {
8445 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
8446 return -1;
8447 }
8448 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008449 if (skip) {
8450 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
8451 end -= skip;
8452 }
8453 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008454 }
willy tarreaua1598082005-12-17 13:08:06 +01008455 else if (*line == '#' || *line == '\n' || *line == '\r') {
8456 /* end of string, end of loop */
8457 *line = 0;
8458 break;
8459 }
willy tarreauc29948c2005-12-17 13:10:27 +01008460 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008461 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01008462 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01008463 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01008464 line++;
8465 args[++arg] = line;
8466 }
8467 else {
8468 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008469 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008470 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008471
willy tarreau9fe663a2005-12-17 13:02:59 +01008472 /* empty line */
8473 if (!**args)
8474 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01008475
willy tarreau9fe663a2005-12-17 13:02:59 +01008476 /* zero out remaining args */
8477 while (++arg < MAX_LINE_ARGS) {
8478 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008479 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008480
willy tarreaua41a8b42005-12-17 14:02:24 +01008481 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01008482 confsect = CFG_LISTEN;
8483 else if (!strcmp(args[0], "global")) /* global config */
8484 confsect = CFG_GLOBAL;
8485 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01008486
willy tarreau9fe663a2005-12-17 13:02:59 +01008487 switch (confsect) {
8488 case CFG_LISTEN:
8489 if (cfg_parse_listen(file, linenum, args) < 0)
8490 return -1;
8491 break;
8492 case CFG_GLOBAL:
8493 if (cfg_parse_global(file, linenum, args) < 0)
8494 return -1;
8495 break;
8496 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01008497 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008498 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008499 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008500
8501
willy tarreau0f7af912005-12-17 12:21:26 +01008502 }
8503 fclose(f);
8504
8505 /*
8506 * Now, check for the integrity of all that we have collected.
8507 */
8508
Willy TARREAU3759f982006-03-01 22:44:17 +01008509 /* will be needed further to delay some tasks */
8510 tv_now(&now);
8511
willy tarreau0f7af912005-12-17 12:21:26 +01008512 if ((curproxy = proxy) == NULL) {
8513 Alert("parsing %s : no <listen> line. Nothing to do !\n",
8514 file);
8515 return -1;
8516 }
8517
8518 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01008519 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01008520 curproxy = curproxy->next;
8521 continue;
8522 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008523
8524 if (curproxy->listen == NULL) {
8525 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);
8526 cfgerr++;
8527 }
8528 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01008529 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01008530 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008531 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
8532 file, curproxy->id);
8533 cfgerr++;
8534 }
8535 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
8536 if (curproxy->options & PR_O_TRANSP) {
8537 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
8538 file, curproxy->id);
8539 cfgerr++;
8540 }
8541 else if (curproxy->srv == NULL) {
8542 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
8543 file, curproxy->id);
8544 cfgerr++;
8545 }
willy tarreaua1598082005-12-17 13:08:06 +01008546 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008547 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
8548 file, curproxy->id);
8549 }
8550 }
8551 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01008552 if (curproxy->cookie_name != NULL) {
8553 Warning("parsing %s : cookie will be ignored for listener %s.\n",
8554 file, curproxy->id);
8555 }
8556 if ((newsrv = curproxy->srv) != NULL) {
8557 Warning("parsing %s : servers will be ignored for listener %s.\n",
8558 file, curproxy->id);
8559 }
willy tarreaue39cd132005-12-17 13:00:18 +01008560 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008561 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
8562 file, curproxy->id);
8563 }
willy tarreaue39cd132005-12-17 13:00:18 +01008564 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008565 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
8566 file, curproxy->id);
8567 }
8568 }
8569 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
8570 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
8571 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
8572 file, curproxy->id);
8573 cfgerr++;
8574 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008575 }
willy tarreaue3f023f2006-04-08 21:52:24 +02008576
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008577 /* first, we will invert the servers list order */
8578 newsrv = NULL;
8579 while (curproxy->srv) {
8580 struct server *next;
8581
8582 next = curproxy->srv->next;
8583 curproxy->srv->next = newsrv;
8584 newsrv = curproxy->srv;
8585 if (!next)
8586 break;
8587 curproxy->srv = next;
8588 }
8589
8590 /* now, newsrv == curproxy->srv */
8591 if (newsrv) {
8592 struct server *srv;
8593 int pgcd;
8594 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02008595
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008596 /* We will factor the weights to reduce the table,
8597 * using Euclide's largest common divisor algorithm
8598 */
8599 pgcd = newsrv->uweight + 1;
8600 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
8601 int t, w;
8602
8603 w = srv->uweight + 1;
8604 while (w) {
8605 t = pgcd % w;
8606 pgcd = w;
8607 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02008608 }
willy tarreau0f7af912005-12-17 12:21:26 +01008609 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008610
8611 act = bck = 0;
8612 for (srv = newsrv; srv; srv = srv->next) {
8613 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
8614 if (srv->state & SRV_BACKUP)
8615 bck += srv->eweight + 1;
8616 else
8617 act += srv->eweight + 1;
8618 }
8619
8620 /* this is the largest map we will ever need for this servers list */
8621 if (act < bck)
8622 act = bck;
8623
8624 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
8625 /* recounts servers and their weights */
8626 recount_servers(curproxy);
8627 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01008628 }
willy tarreau25c4ea52005-12-18 00:49:49 +01008629
8630 if (curproxy->options & PR_O_LOGASAP)
8631 curproxy->to_log &= ~LW_BYTES;
8632
willy tarreau8337c6b2005-12-17 13:41:01 +01008633 if (curproxy->errmsg.msg400 == NULL) {
8634 curproxy->errmsg.msg400 = (char *)HTTP_400;
8635 curproxy->errmsg.len400 = strlen(HTTP_400);
8636 }
8637 if (curproxy->errmsg.msg403 == NULL) {
8638 curproxy->errmsg.msg403 = (char *)HTTP_403;
8639 curproxy->errmsg.len403 = strlen(HTTP_403);
8640 }
8641 if (curproxy->errmsg.msg408 == NULL) {
8642 curproxy->errmsg.msg408 = (char *)HTTP_408;
8643 curproxy->errmsg.len408 = strlen(HTTP_408);
8644 }
8645 if (curproxy->errmsg.msg500 == NULL) {
8646 curproxy->errmsg.msg500 = (char *)HTTP_500;
8647 curproxy->errmsg.len500 = strlen(HTTP_500);
8648 }
8649 if (curproxy->errmsg.msg502 == NULL) {
8650 curproxy->errmsg.msg502 = (char *)HTTP_502;
8651 curproxy->errmsg.len502 = strlen(HTTP_502);
8652 }
8653 if (curproxy->errmsg.msg503 == NULL) {
8654 curproxy->errmsg.msg503 = (char *)HTTP_503;
8655 curproxy->errmsg.len503 = strlen(HTTP_503);
8656 }
8657 if (curproxy->errmsg.msg504 == NULL) {
8658 curproxy->errmsg.msg504 = (char *)HTTP_504;
8659 curproxy->errmsg.len504 = strlen(HTTP_504);
8660 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008661
willy tarreau59a6cc22006-05-12 01:29:08 +02008662 /*
8663 * If this server supports a maxconn parameter, it needs a dedicated
8664 * tasks to fill the emptied slots when a connection leaves.
8665 */
8666 newsrv = curproxy->srv;
8667 while (newsrv != NULL) {
8668 if (newsrv->maxconn > 0) {
8669 struct task *t;
8670
8671 if ((t = pool_alloc(task)) == NULL) {
8672 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8673 return -1;
8674 }
8675
8676 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
8677 t->wq = LIST_HEAD(wait_queue[1]); /* already assigned to the eternity queue */
8678 t->state = TASK_IDLE;
8679 t->process = process_srv_queue;
8680 t->context = newsrv;
8681 newsrv->queue_mgt = t;
8682
8683 /* never run it unless specifically woken up */
8684 tv_eternity(&t->expire);
8685 task_queue(t);
8686 }
8687 newsrv = newsrv->next;
8688 }
8689
Willy TARREAU3759f982006-03-01 22:44:17 +01008690 /* now we'll start this proxy's health checks if any */
8691 /* 1- count the checkers to run simultaneously */
8692 nbchk = 0;
8693 mininter = 0;
8694 newsrv = curproxy->srv;
8695 while (newsrv != NULL) {
8696 if (newsrv->state & SRV_CHECKED) {
8697 if (!mininter || mininter > newsrv->inter)
8698 mininter = newsrv->inter;
8699 nbchk++;
8700 }
8701 newsrv = newsrv->next;
8702 }
8703
8704 /* 2- start them as far as possible from each others while respecting
8705 * their own intervals. For this, we will start them after their own
8706 * interval added to the min interval divided by the number of servers,
8707 * weighted by the server's position in the list.
8708 */
8709 if (nbchk > 0) {
8710 struct task *t;
8711 int srvpos;
8712
8713 newsrv = curproxy->srv;
8714 srvpos = 0;
8715 while (newsrv != NULL) {
8716 /* should this server be checked ? */
8717 if (newsrv->state & SRV_CHECKED) {
8718 if ((t = pool_alloc(task)) == NULL) {
8719 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8720 return -1;
8721 }
8722
8723 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02008724 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
Willy TARREAU3759f982006-03-01 22:44:17 +01008725 t->state = TASK_IDLE;
8726 t->process = process_chk;
8727 t->context = newsrv;
8728
8729 /* check this every ms */
8730 tv_delayfrom(&t->expire, &now,
8731 newsrv->inter + mininter * srvpos / nbchk);
8732 task_queue(t);
8733 //task_wakeup(&rq, t);
8734 srvpos++;
8735 }
8736 newsrv = newsrv->next;
8737 }
8738 }
8739
willy tarreau0f7af912005-12-17 12:21:26 +01008740 curproxy = curproxy->next;
8741 }
8742 if (cfgerr > 0) {
8743 Alert("Errors found in configuration file, aborting.\n");
8744 return -1;
8745 }
8746 else
8747 return 0;
8748}
8749
8750
8751/*
8752 * This function initializes all the necessary variables. It only returns
8753 * if everything is OK. If something fails, it exits.
8754 */
8755void init(int argc, char **argv) {
8756 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01008757 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01008758 char *old_argv = *argv;
8759 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008760 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008761
8762 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01008763 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01008764 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01008765 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01008766 exit(1);
8767 }
8768
willy tarreau746e26b2006-03-25 11:14:35 +01008769#ifdef HAPROXY_MEMMAX
8770 global.rlimit_memmax = HAPROXY_MEMMAX;
8771#endif
8772
Willy TARREAUa9e75f62006-03-01 22:27:48 +01008773 /* initialize the libc's localtime structures once for all so that we
8774 * won't be missing memory if we want to send alerts under OOM conditions.
8775 */
8776 tv_now(&now);
8777 localtime(&now.tv_sec);
8778
willy tarreau4302f492005-12-18 01:00:37 +01008779 /* initialize the log header encoding map : '{|}"#' should be encoded with
8780 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
8781 * URL encoding only requires '"', '#' to be encoded as well as non-
8782 * printable characters above.
8783 */
8784 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
8785 memset(url_encode_map, 0, sizeof(url_encode_map));
8786 for (i = 0; i < 32; i++) {
8787 FD_SET(i, hdr_encode_map);
8788 FD_SET(i, url_encode_map);
8789 }
8790 for (i = 127; i < 256; i++) {
8791 FD_SET(i, hdr_encode_map);
8792 FD_SET(i, url_encode_map);
8793 }
8794
8795 tmp = "\"#{|}";
8796 while (*tmp) {
8797 FD_SET(*tmp, hdr_encode_map);
8798 tmp++;
8799 }
8800
8801 tmp = "\"#";
8802 while (*tmp) {
8803 FD_SET(*tmp, url_encode_map);
8804 tmp++;
8805 }
8806
willy tarreau64a3cc32005-12-18 01:13:11 +01008807 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8808#if defined(ENABLE_POLL)
8809 cfg_polling_mechanism |= POLL_USE_POLL;
8810#endif
8811#if defined(ENABLE_EPOLL)
8812 cfg_polling_mechanism |= POLL_USE_EPOLL;
8813#endif
8814
willy tarreau0f7af912005-12-17 12:21:26 +01008815 pid = getpid();
8816 progname = *argv;
8817 while ((tmp = strchr(progname, '/')) != NULL)
8818 progname = tmp + 1;
8819
8820 argc--; argv++;
8821 while (argc > 0) {
8822 char *flag;
8823
8824 if (**argv == '-') {
8825 flag = *argv+1;
8826
8827 /* 1 arg */
8828 if (*flag == 'v') {
8829 display_version();
8830 exit(0);
8831 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008832#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008833 else if (*flag == 'd' && flag[1] == 'e')
8834 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008835#endif
8836#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008837 else if (*flag == 'd' && flag[1] == 'p')
8838 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008839#endif
willy tarreau982249e2005-12-18 00:57:06 +01008840 else if (*flag == 'V')
8841 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008842 else if (*flag == 'd' && flag[1] == 'b')
8843 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008844 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008845 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008846 else if (*flag == 'c')
8847 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008848 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008849 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008850 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008851 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01008852 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8853 /* list of pids to finish ('f') or terminate ('t') */
8854
8855 if (flag[1] == 'f')
8856 oldpids_sig = SIGUSR1; /* finish then exit */
8857 else
8858 oldpids_sig = SIGTERM; /* terminate immediately */
8859 argv++; argc--;
8860
8861 if (argc > 0) {
8862 oldpids = calloc(argc, sizeof(int));
8863 while (argc > 0) {
8864 oldpids[nb_oldpids] = atol(*argv);
8865 if (oldpids[nb_oldpids] <= 0)
8866 usage(old_argv);
8867 argc--; argv++;
8868 nb_oldpids++;
8869 }
8870 }
8871 }
willy tarreau2c513732006-04-15 19:25:16 +02008872#if STATTIME > 0
8873 else if (*flag == 's')
8874 arg_mode |= MODE_STATS;
8875 else if (*flag == 'l')
8876 arg_mode |= MODE_LOG;
8877#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008878 else { /* >=2 args */
8879 argv++; argc--;
8880 if (argc == 0)
8881 usage(old_argv);
8882
8883 switch (*flag) {
8884 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008885 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008886 case 'N' : cfg_maxpconn = atol(*argv); break;
8887 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008888 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008889 default: usage(old_argv);
8890 }
8891 }
8892 }
8893 else
8894 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008895 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008896 }
8897
willy tarreaud0fb4652005-12-18 01:32:04 +01008898 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008899 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8900 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008901
willy tarreau0f7af912005-12-17 12:21:26 +01008902 if (!cfg_cfgfile)
8903 usage(old_argv);
8904
8905 gethostname(hostname, MAX_HOSTNAME_LEN);
8906
willy tarreau12350152005-12-18 01:03:27 +01008907 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008908 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008909 if (readcfgfile(cfg_cfgfile) < 0) {
8910 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8911 exit(1);
8912 }
willy tarreau12350152005-12-18 01:03:27 +01008913 if (have_appsession)
8914 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008915
willy tarreau982249e2005-12-18 00:57:06 +01008916 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008917 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8918 exit(0);
8919 }
8920
willy tarreau9fe663a2005-12-17 13:02:59 +01008921 if (cfg_maxconn > 0)
8922 global.maxconn = cfg_maxconn;
8923
willy tarreaufe2c5c12005-12-17 14:14:34 +01008924 if (cfg_pidfile) {
8925 if (global.pidfile)
8926 free(global.pidfile);
8927 global.pidfile = strdup(cfg_pidfile);
8928 }
8929
willy tarreau9fe663a2005-12-17 13:02:59 +01008930 if (global.maxconn == 0)
8931 global.maxconn = DEFAULT_MAXCONN;
8932
Willy TARREAU203b0b62006-03-12 18:00:28 +01008933 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008934
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008935 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008936 /* command line debug mode inhibits configuration mode */
8937 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8938 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008939 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8940 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008941
8942 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8943 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8944 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8945 }
8946
8947 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008948 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8949 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008950 global.nbproc = 1;
8951 }
8952
8953 if (global.nbproc < 1)
8954 global.nbproc = 1;
8955
willy tarreau0f7af912005-12-17 12:21:26 +01008956 StaticReadEvent = (fd_set *)calloc(1,
8957 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008958 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008959 StaticWriteEvent = (fd_set *)calloc(1,
8960 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008961 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008962
8963 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008964 sizeof(struct fdtab) * (global.maxsock));
8965 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008966 fdtab[i].state = FD_STCLOSE;
8967 }
8968}
8969
8970/*
willy tarreau41310e72006-03-25 18:17:56 +01008971 * this function starts all the proxies. Its return value is composed from
8972 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8973 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008974 */
willy tarreau41310e72006-03-25 18:17:56 +01008975int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008976 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008977 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008978 int err = ERR_NONE;
8979 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008980
8981 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008982 if (curproxy->state != PR_STNEW)
8983 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01008984
willy tarreau41310e72006-03-25 18:17:56 +01008985 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01008986 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008987 if (listener->fd != -1)
8988 continue; /* already initialized */
8989
8990 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
8991 if (verbose)
8992 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8993 curproxy->id);
8994 err |= ERR_RETRYABLE;
8995 pxerr |= 1;
8996 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008997 }
willy tarreau0f7af912005-12-17 12:21:26 +01008998
willy tarreaua41a8b42005-12-17 14:02:24 +01008999 if (fd >= global.maxsock) {
9000 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
9001 curproxy->id);
9002 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009003 err |= ERR_FATAL;
9004 pxerr |= 1;
9005 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009006 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009007
willy tarreaua41a8b42005-12-17 14:02:24 +01009008 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
9009 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
9010 (char *) &one, sizeof(one)) == -1)) {
9011 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
9012 curproxy->id);
9013 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009014 err |= ERR_FATAL;
9015 pxerr |= 1;
9016 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009017 }
willy tarreau0f7af912005-12-17 12:21:26 +01009018
willy tarreaua41a8b42005-12-17 14:02:24 +01009019 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
9020 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
9021 curproxy->id);
9022 }
willy tarreau0f7af912005-12-17 12:21:26 +01009023
willy tarreaua41a8b42005-12-17 14:02:24 +01009024 if (bind(fd,
9025 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01009026 listener->addr.ss_family == AF_INET6 ?
9027 sizeof(struct sockaddr_in6) :
9028 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009029 if (verbose)
9030 Alert("cannot bind socket for proxy %s. Aborting.\n",
9031 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009032 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009033 err |= ERR_RETRYABLE;
9034 pxerr |= 1;
9035 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009036 }
willy tarreau0f7af912005-12-17 12:21:26 +01009037
willy tarreaua41a8b42005-12-17 14:02:24 +01009038 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009039 if (verbose)
9040 Alert("cannot listen to socket for proxy %s. Aborting.\n",
9041 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009042 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009043 err |= ERR_RETRYABLE;
9044 pxerr |= 1;
9045 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009046 }
willy tarreau0f7af912005-12-17 12:21:26 +01009047
willy tarreau41310e72006-03-25 18:17:56 +01009048 /* the socket is ready */
9049 listener->fd = fd;
9050
willy tarreaua41a8b42005-12-17 14:02:24 +01009051 /* the function for the accept() event */
9052 fdtab[fd].read = &event_accept;
9053 fdtab[fd].write = NULL; /* never called */
9054 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01009055 fdtab[fd].state = FD_STLISTEN;
9056 FD_SET(fd, StaticReadEvent);
9057 fd_insert(fd);
9058 listeners++;
9059 }
willy tarreau41310e72006-03-25 18:17:56 +01009060
9061 if (!pxerr) {
9062 curproxy->state = PR_STRUN;
9063 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
9064 }
willy tarreau0f7af912005-12-17 12:21:26 +01009065 }
willy tarreau41310e72006-03-25 18:17:56 +01009066
9067 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01009068}
9069
willy tarreaub952e1d2005-12-18 01:31:20 +01009070int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01009071
9072 appsess *temp1,*temp2;
9073 temp1 = (appsess *)key1;
9074 temp2 = (appsess *)key2;
9075
9076 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
9077 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
9078
9079 return (strcmp(temp1->sessid,temp2->sessid) == 0);
9080}/* end match_str */
9081
willy tarreaub952e1d2005-12-18 01:31:20 +01009082void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01009083 appsess *temp1;
9084
9085 //printf("destroy called\n");
9086 temp1 = (appsess *)data;
9087
9088 if (temp1->sessid)
9089 pool_free_to(apools.sessid, temp1->sessid);
9090
9091 if (temp1->serverid)
9092 pool_free_to(apools.serverid, temp1->serverid);
9093
9094 pool_free(appsess, temp1);
9095} /* end destroy */
9096
9097void appsession_cleanup( void )
9098{
9099 struct proxy *p = proxy;
9100
9101 while(p) {
9102 chtbl_destroy(&(p->htbl_proxy));
9103 p = p->next;
9104 }
9105}/* end appsession_cleanup() */
9106
9107void pool_destroy(void **pool)
9108{
9109 void *temp, *next;
9110 next = pool;
9111 while (next) {
9112 temp = next;
9113 next = *(void **)temp;
9114 free(temp);
9115 }
9116}/* end pool_destroy() */
9117
willy tarreaub952e1d2005-12-18 01:31:20 +01009118void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01009119 struct proxy *p = proxy;
9120 struct cap_hdr *h,*h_next;
9121 struct server *s,*s_next;
9122 struct listener *l,*l_next;
9123
9124 while (p) {
9125 if (p->id)
9126 free(p->id);
9127
9128 if (p->check_req)
9129 free(p->check_req);
9130
9131 if (p->cookie_name)
9132 free(p->cookie_name);
9133
9134 if (p->capture_name)
9135 free(p->capture_name);
9136
9137 /* only strup if the user have set in config.
9138 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01009139 if (p->errmsg.msg400) free(p->errmsg.msg400);
9140 if (p->errmsg.msg403) free(p->errmsg.msg403);
9141 if (p->errmsg.msg408) free(p->errmsg.msg408);
9142 if (p->errmsg.msg500) free(p->errmsg.msg500);
9143 if (p->errmsg.msg502) free(p->errmsg.msg502);
9144 if (p->errmsg.msg503) free(p->errmsg.msg503);
9145 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01009146 */
9147 if (p->appsession_name)
9148 free(p->appsession_name);
9149
9150 h = p->req_cap;
9151 while (h) {
9152 h_next = h->next;
9153 if (h->name)
9154 free(h->name);
9155 pool_destroy(h->pool);
9156 free(h);
9157 h = h_next;
9158 }/* end while(h) */
9159
9160 h = p->rsp_cap;
9161 while (h) {
9162 h_next = h->next;
9163 if (h->name)
9164 free(h->name);
9165
9166 pool_destroy(h->pool);
9167 free(h);
9168 h = h_next;
9169 }/* end while(h) */
9170
9171 s = p->srv;
9172 while (s) {
9173 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01009174 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01009175 free(s->id);
9176
willy tarreaub952e1d2005-12-18 01:31:20 +01009177 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01009178 free(s->cookie);
9179
9180 free(s);
9181 s = s_next;
9182 }/* end while(s) */
9183
9184 l = p->listen;
9185 while (l) {
9186 l_next = l->next;
9187 free(l);
9188 l = l_next;
9189 }/* end while(l) */
9190
9191 pool_destroy((void **) p->req_cap_pool);
9192 pool_destroy((void **) p->rsp_cap_pool);
9193 p = p->next;
9194 }/* end while(p) */
9195
9196 if (global.chroot) free(global.chroot);
9197 if (global.pidfile) free(global.pidfile);
9198
willy tarreau12350152005-12-18 01:03:27 +01009199 if (StaticReadEvent) free(StaticReadEvent);
9200 if (StaticWriteEvent) free(StaticWriteEvent);
9201 if (fdtab) free(fdtab);
9202
9203 pool_destroy(pool_session);
9204 pool_destroy(pool_buffer);
9205 pool_destroy(pool_fdtab);
9206 pool_destroy(pool_requri);
9207 pool_destroy(pool_task);
9208 pool_destroy(pool_capture);
9209 pool_destroy(pool_appsess);
9210
9211 if (have_appsession) {
9212 pool_destroy(apools.serverid);
9213 pool_destroy(apools.sessid);
9214 }
9215} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01009216
willy tarreau41310e72006-03-25 18:17:56 +01009217/* sends the signal <sig> to all pids found in <oldpids> */
9218static void tell_old_pids(int sig) {
9219 int p;
9220 for (p = 0; p < nb_oldpids; p++)
9221 kill(oldpids[p], sig);
9222}
9223
willy tarreau0f7af912005-12-17 12:21:26 +01009224int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01009225 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01009226 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009227 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009228 init(argc, argv);
9229
willy tarreau0f7af912005-12-17 12:21:26 +01009230 signal(SIGQUIT, dump);
9231 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01009232 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01009233#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01009234 signal(SIGINT, sig_int);
9235 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01009236#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009237
9238 /* on very high loads, a sigpipe sometimes happen just between the
9239 * getsockopt() which tells "it's OK to write", and the following write :-(
9240 */
willy tarreau3242e862005-12-17 12:27:53 +01009241#ifndef MSG_NOSIGNAL
9242 signal(SIGPIPE, SIG_IGN);
9243#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009244
willy tarreau41310e72006-03-25 18:17:56 +01009245 /* We will loop at most 100 times with 10 ms delay each time.
9246 * That's at most 1 second. We only send a signal to old pids
9247 * if we cannot grab at least one port.
9248 */
9249 retry = MAX_START_RETRIES;
9250 err = ERR_NONE;
9251 while (retry >= 0) {
9252 struct timeval w;
9253 err = start_proxies(retry == 0 || nb_oldpids == 0);
9254 if (err != ERR_RETRYABLE)
9255 break;
9256 if (nb_oldpids == 0)
9257 break;
9258
9259 tell_old_pids(SIGTTOU);
9260 /* give some time to old processes to stop listening */
9261 w.tv_sec = 0;
9262 w.tv_usec = 10*1000;
9263 select(0, NULL, NULL, NULL, &w);
9264 retry--;
9265 }
9266
9267 /* Note: start_proxies() sends an alert when it fails. */
9268 if (err != ERR_NONE) {
9269 if (retry != MAX_START_RETRIES && nb_oldpids)
9270 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01009271 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01009272 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009273
9274 if (listeners == 0) {
9275 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009276 /* Note: we don't have to send anything to the old pids because we
9277 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01009278 exit(1);
9279 }
9280
willy tarreaudbd3bef2006-01-20 19:35:18 +01009281 /* prepare pause/play signals */
9282 signal(SIGTTOU, sig_pause);
9283 signal(SIGTTIN, sig_listen);
9284
Willy TARREAUe3283d12006-03-01 22:15:29 +01009285 if (global.mode & MODE_DAEMON) {
9286 global.mode &= ~MODE_VERBOSE;
9287 global.mode |= MODE_QUIET;
9288 }
9289
willy tarreaud0fb4652005-12-18 01:32:04 +01009290 /* MODE_QUIET can inhibit alerts and warnings below this line */
9291
9292 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01009293 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01009294 /* detach from the tty */
9295 fclose(stdin); fclose(stdout); fclose(stderr);
9296 close(0); close(1); close(2);
9297 }
willy tarreau0f7af912005-12-17 12:21:26 +01009298
willy tarreaufe2c5c12005-12-17 14:14:34 +01009299 /* open log & pid files before the chroot */
9300 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
9301 int pidfd;
9302 unlink(global.pidfile);
9303 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
9304 if (pidfd < 0) {
9305 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01009306 if (nb_oldpids)
9307 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01009308 exit(1);
9309 }
9310 pidfile = fdopen(pidfd, "w");
9311 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009312
9313 /* chroot if needed */
9314 if (global.chroot != NULL) {
9315 if (chroot(global.chroot) == -1) {
9316 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01009317 if (nb_oldpids)
9318 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01009319 }
9320 chdir("/");
9321 }
9322
willy tarreaub1285d52005-12-18 01:20:14 +01009323 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01009324 if (!global.rlimit_nofile)
9325 global.rlimit_nofile = global.maxsock;
9326
willy tarreaub1285d52005-12-18 01:20:14 +01009327 if (global.rlimit_nofile) {
9328 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
9329 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
9330 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
9331 }
willy tarreau746e26b2006-03-25 11:14:35 +01009332 }
9333
9334 if (global.rlimit_memmax) {
9335 limit.rlim_cur = limit.rlim_max =
9336 global.rlimit_memmax * 1048576 / global.nbproc;
9337#ifdef RLIMIT_AS
9338 if (setrlimit(RLIMIT_AS, &limit) == -1) {
9339 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9340 argv[0], global.rlimit_memmax);
9341 }
9342#else
9343 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
9344 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9345 argv[0], global.rlimit_memmax);
9346 }
9347#endif
willy tarreaub1285d52005-12-18 01:20:14 +01009348 }
9349
willy tarreau41310e72006-03-25 18:17:56 +01009350 if (nb_oldpids)
9351 tell_old_pids(oldpids_sig);
9352
9353 /* Note that any error at this stage will be fatal because we will not
9354 * be able to restart the old pids.
9355 */
9356
willy tarreau9fe663a2005-12-17 13:02:59 +01009357 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01009358 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009359 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
9360 exit(1);
9361 }
9362
willy tarreau036e1ce2005-12-17 13:46:33 +01009363 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009364 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
9365 exit(1);
9366 }
9367
willy tarreaub1285d52005-12-18 01:20:14 +01009368 /* check ulimits */
9369 limit.rlim_cur = limit.rlim_max = 0;
9370 getrlimit(RLIMIT_NOFILE, &limit);
9371 if (limit.rlim_cur < global.maxsock) {
9372 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",
9373 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
9374 }
9375
willy tarreau9fe663a2005-12-17 13:02:59 +01009376 if (global.mode & MODE_DAEMON) {
9377 int ret = 0;
9378 int proc;
9379
9380 /* the father launches the required number of processes */
9381 for (proc = 0; proc < global.nbproc; proc++) {
9382 ret = fork();
9383 if (ret < 0) {
9384 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009385 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01009386 exit(1); /* there has been an error */
9387 }
9388 else if (ret == 0) /* child breaks here */
9389 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009390 if (pidfile != NULL) {
9391 fprintf(pidfile, "%d\n", ret);
9392 fflush(pidfile);
9393 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009394 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01009395 /* close the pidfile both in children and father */
9396 if (pidfile != NULL)
9397 fclose(pidfile);
9398 free(global.pidfile);
9399
willy tarreau9fe663a2005-12-17 13:02:59 +01009400 if (proc == global.nbproc)
9401 exit(0); /* parent must leave */
9402
willy tarreau750a4722005-12-17 13:21:24 +01009403 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
9404 * that we can detach from the TTY. We MUST NOT do it in other cases since
9405 * it would have already be done, and 0-2 would have been affected to listening
9406 * sockets
9407 */
9408 if (!(global.mode & MODE_QUIET)) {
9409 /* detach from the tty */
9410 fclose(stdin); fclose(stdout); fclose(stderr);
9411 close(0); close(1); close(2); /* close all fd's */
9412 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
9413 }
willy tarreaua1598082005-12-17 13:08:06 +01009414 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01009415 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01009416 }
9417
willy tarreau1c2ad212005-12-18 01:11:29 +01009418#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009419 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009420 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
9421 epoll_loop(POLL_LOOP_ACTION_RUN);
9422 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009423 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009424 }
9425 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01009426 Warning("epoll() is not available. Using poll()/select() instead.\n");
9427 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009428 }
9429 }
9430#endif
9431
9432#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009433 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009434 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
9435 poll_loop(POLL_LOOP_ACTION_RUN);
9436 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009437 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009438 }
9439 else {
9440 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01009441 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009442 }
9443 }
9444#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01009445 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009446 if (select_loop(POLL_LOOP_ACTION_INIT)) {
9447 select_loop(POLL_LOOP_ACTION_RUN);
9448 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009449 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01009450 }
9451 }
9452
willy tarreau0f7af912005-12-17 12:21:26 +01009453
willy tarreau12350152005-12-18 01:03:27 +01009454 /* Free all Hash Keys and all Hash elements */
9455 appsession_cleanup();
9456 /* Do some cleanup */
9457 deinit();
9458
willy tarreau0f7af912005-12-17 12:21:26 +01009459 exit(0);
9460}
willy tarreau12350152005-12-18 01:03:27 +01009461
9462#if defined(DEBUG_HASH)
9463static void print_table(const CHTbl *htbl) {
9464
9465 ListElmt *element;
9466 int i;
9467 appsess *asession;
9468
9469 /*****************************************************************************
9470 * *
9471 * Display the chained hash table. *
9472 * *
9473 *****************************************************************************/
9474
9475 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
9476
9477 for (i = 0; i < TBLSIZ; i++) {
9478 fprintf(stdout, "Bucket[%03d]\n", i);
9479
9480 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9481 //fprintf(stdout, "%c", *(char *)list_data(element));
9482 asession = (appsess *)list_data(element);
9483 fprintf(stdout, "ELEM :%s:", asession->sessid);
9484 fprintf(stdout, " Server :%s: \n", asession->serverid);
9485 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
9486 }
9487
9488 fprintf(stdout, "\n");
9489 }
9490 return;
9491} /* end print_table */
9492#endif
9493
9494static int appsession_init(void)
9495{
9496 static int initialized = 0;
9497 int idlen;
9498 struct server *s;
9499 struct proxy *p = proxy;
9500
9501 if (!initialized) {
9502 if (!appsession_task_init()) {
9503 apools.sessid = NULL;
9504 apools.serverid = NULL;
9505 apools.ser_waste = 0;
9506 apools.ser_use = 0;
9507 apools.ser_msize = sizeof(void *);
9508 apools.ses_waste = 0;
9509 apools.ses_use = 0;
9510 apools.ses_msize = sizeof(void *);
9511 while (p) {
9512 s = p->srv;
9513 if (apools.ses_msize < p->appsession_len)
9514 apools.ses_msize = p->appsession_len;
9515 while (s) {
9516 idlen = strlen(s->id);
9517 if (apools.ser_msize < idlen)
9518 apools.ser_msize = idlen;
9519 s = s->next;
9520 }
9521 p = p->next;
9522 }
9523 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
9524 apools.ses_msize ++;
9525 }
9526 else {
9527 fprintf(stderr, "appsession_task_init failed\n");
9528 return -1;
9529 }
9530 initialized ++;
9531 }
9532 return 0;
9533}
9534
9535static int appsession_task_init(void)
9536{
9537 static int initialized = 0;
9538 struct task *t;
9539 if (!initialized) {
9540 if ((t = pool_alloc(task)) == NULL)
9541 return -1;
9542 t->next = t->prev = t->rqnext = NULL;
willy tarreau5e698ef2006-05-02 14:51:00 +02009543 t->wq = LIST_HEAD(wait_queue[0]);
willy tarreau12350152005-12-18 01:03:27 +01009544 t->state = TASK_IDLE;
9545 t->context = NULL;
9546 tv_delayfrom(&t->expire, &now, TBLCHKINT);
9547 task_queue(t);
9548 t->process = appsession_refresh;
9549 initialized ++;
9550 }
9551 return 0;
9552}
9553
9554static int appsession_refresh(struct task *t) {
9555 struct proxy *p = proxy;
9556 CHTbl *htbl;
9557 ListElmt *element, *last;
9558 int i;
9559 appsess *asession;
9560 void *data;
9561
9562 while (p) {
9563 if (p->appsession_name != NULL) {
9564 htbl = &p->htbl_proxy;
9565 /* if we ever give up the use of TBLSIZ, we need to change this */
9566 for (i = 0; i < TBLSIZ; i++) {
9567 last = NULL;
9568 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9569 asession = (appsess *)list_data(element);
9570 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
9571 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
9572 int len;
9573 /*
9574 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
9575 */
9576 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
9577 asession->sessid, asession->serverid?asession->serverid:"(null)");
9578 write(1, trash, len);
9579 }
9580 /* delete the expired element from within the hash table */
9581 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
9582 && (htbl->table[i].destroy != NULL)) {
9583 htbl->table[i].destroy(data);
9584 }
9585 if (last == NULL) {/* patient lost his head, get a new one */
9586 element = list_head(&htbl->table[i]);
9587 if (element == NULL) break; /* no heads left, go to next patient */
9588 }
9589 else
9590 element = last;
9591 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
9592 else
9593 last = element;
9594 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
9595 }
9596 }
9597 p = p->next;
9598 }
9599 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
9600 return TBLCHKINT;
9601} /* end appsession_refresh */
9602
willy tarreau18a957c2006-04-12 19:26:23 +02009603
9604/*
9605 * Local variables:
9606 * c-indent-level: 4
9607 * c-basic-offset: 4
9608 * End:
9609 */