blob: 66deec92444ccb279661809cbdd538811bcbb48e [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 tarreauc3a2e072006-05-13 18:51:38 +020092#define HAPROXY_VERSION "1.2.13"
willy tarreaubfad5742006-03-23 14:19:11 +010093#endif
94
95#ifndef HAPROXY_DATE
willy tarreauc3a2e072006-05-13 18:51:38 +020096#define HAPROXY_DATE "2006/05/13"
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 tarreau5f15c552006-05-13 18:37:04 +02003003 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%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 tarreau5f15c552006-05-13 18:37:04 +02003011 (s->logs.t_queue >= 0) ? s->logs.t_queue : -1,
3012 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003013 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3014 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01003015 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01003016 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreau5e69b162006-05-12 19:49:37 +02003017 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3018 s->logs.srv_queue_size, s->logs.prx_queue_size);
willy tarreaua1598082005-12-17 13:08:06 +01003019 }
3020
3021 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003022}
3023
willy tarreaue39cd132005-12-17 13:00:18 +01003024
3025/*
willy tarreau0f7af912005-12-17 12:21:26 +01003026 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01003027 * to an accept. It tries to accept as many connections as possible.
3028 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01003029 */
3030int event_accept(int fd) {
3031 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003032 struct session *s;
3033 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01003034 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01003035 int max_accept;
3036
3037 if (global.nbproc > 1)
3038 max_accept = 8; /* let other processes catch some connections too */
3039 else
3040 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003041
willy tarreauc2becdc2006-03-19 19:36:48 +01003042 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003043 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003044 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01003045
willy tarreaub1285d52005-12-18 01:20:14 +01003046 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
3047 switch (errno) {
3048 case EAGAIN:
3049 case EINTR:
3050 case ECONNABORTED:
3051 return 0; /* nothing more to accept */
3052 case ENFILE:
3053 send_log(p, LOG_EMERG,
3054 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
3055 p->id, maxfd);
3056 return 0;
3057 case EMFILE:
3058 send_log(p, LOG_EMERG,
3059 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
3060 p->id, maxfd);
3061 return 0;
3062 case ENOBUFS:
3063 case ENOMEM:
3064 send_log(p, LOG_EMERG,
3065 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
3066 p->id, maxfd);
3067 return 0;
3068 default:
3069 return 0;
3070 }
3071 }
willy tarreau0f7af912005-12-17 12:21:26 +01003072
willy tarreau5cbea6f2005-12-17 12:48:26 +01003073 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
3074 Alert("out of memory in event_accept().\n");
3075 FD_CLR(fd, StaticReadEvent);
3076 p->state = PR_STIDLE;
3077 close(cfd);
3078 return 0;
3079 }
willy tarreau0f7af912005-12-17 12:21:26 +01003080
willy tarreaub1285d52005-12-18 01:20:14 +01003081 /* if this session comes from a known monitoring system, we want to ignore
3082 * it as soon as possible, which means closing it immediately for TCP.
3083 */
3084 s->flags = 0;
3085 if (addr.ss_family == AF_INET &&
3086 p->mon_mask.s_addr &&
3087 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
3088 if (p->mode == PR_MODE_TCP) {
3089 close(cfd);
3090 pool_free(session, s);
3091 continue;
3092 }
3093 s->flags |= SN_MONITOR;
3094 }
3095
willy tarreau5cbea6f2005-12-17 12:48:26 +01003096 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3097 Alert("out of memory in event_accept().\n");
3098 FD_CLR(fd, StaticReadEvent);
3099 p->state = PR_STIDLE;
3100 close(cfd);
3101 pool_free(session, s);
3102 return 0;
3103 }
willy tarreau0f7af912005-12-17 12:21:26 +01003104
willy tarreau5cbea6f2005-12-17 12:48:26 +01003105 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01003106 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003107 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
3108 close(cfd);
3109 pool_free(task, t);
3110 pool_free(session, s);
3111 return 0;
3112 }
willy tarreau0f7af912005-12-17 12:21:26 +01003113
willy tarreau5cbea6f2005-12-17 12:48:26 +01003114 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
3115 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
3116 (char *) &one, sizeof(one)) == -1)) {
3117 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
3118 close(cfd);
3119 pool_free(task, t);
3120 pool_free(session, s);
3121 return 0;
3122 }
willy tarreau0f7af912005-12-17 12:21:26 +01003123
willy tarreaub952e1d2005-12-18 01:31:20 +01003124 if (p->options & PR_O_TCP_CLI_KA)
3125 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
3126
willy tarreau9fe663a2005-12-17 13:02:59 +01003127 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02003128 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
willy tarreau9fe663a2005-12-17 13:02:59 +01003129 t->state = TASK_IDLE;
3130 t->process = process_session;
3131 t->context = s;
3132
3133 s->task = t;
3134 s->proxy = p;
3135 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
3136 s->srv_state = SV_STIDLE;
3137 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01003138
willy tarreau9fe663a2005-12-17 13:02:59 +01003139 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
3140 s->cli_fd = cfd;
3141 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003142 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01003143 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01003144
willy tarreaub1285d52005-12-18 01:20:14 +01003145 if (s->flags & SN_MONITOR)
3146 s->logs.logwait = 0;
3147 else
3148 s->logs.logwait = p->to_log;
3149
willy tarreaua1598082005-12-17 13:08:06 +01003150 s->logs.tv_accept = now;
3151 s->logs.t_request = -1;
willy tarreauf32f5242006-05-02 22:54:52 +02003152 s->logs.t_queue = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003153 s->logs.t_connect = -1;
3154 s->logs.t_data = -1;
3155 s->logs.t_close = 0;
3156 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01003157 s->logs.cli_cookie = NULL;
3158 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01003159 s->logs.status = -1;
3160 s->logs.bytes = 0;
willy tarreau5e69b162006-05-12 19:49:37 +02003161 s->logs.prx_queue_size = 0; /* we get the number of pending conns before us */
3162 s->logs.srv_queue_size = 0; /* we will get this number soon */
willy tarreau9fe663a2005-12-17 13:02:59 +01003163
willy tarreau2f6ba652005-12-17 13:57:42 +01003164 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02003165 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01003166
willy tarreau4302f492005-12-18 01:00:37 +01003167 if (p->nb_req_cap > 0) {
3168 if ((s->req_cap =
3169 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
3170 == NULL) { /* no memory */
3171 close(cfd); /* nothing can be done for this fd without memory */
3172 pool_free(task, t);
3173 pool_free(session, s);
3174 return 0;
3175 }
3176 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
3177 }
3178 else
3179 s->req_cap = NULL;
3180
3181 if (p->nb_rsp_cap > 0) {
3182 if ((s->rsp_cap =
3183 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
3184 == NULL) { /* no memory */
3185 if (s->req_cap != NULL)
3186 pool_free_to(p->req_cap_pool, s->req_cap);
3187 close(cfd); /* nothing can be done for this fd without memory */
3188 pool_free(task, t);
3189 pool_free(session, s);
3190 return 0;
3191 }
3192 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
3193 }
3194 else
3195 s->rsp_cap = NULL;
3196
willy tarreau5cbea6f2005-12-17 12:48:26 +01003197 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
3198 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003199 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003200 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01003201
willy tarreau8a86dbf2005-12-18 00:45:59 +01003202 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003203 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003204 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003205 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01003206
willy tarreau9fe663a2005-12-17 13:02:59 +01003207 if (p->to_log) {
3208 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01003209 if (s->logs.logwait & LW_CLIP)
3210 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01003211 sess_log(s);
3212 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01003213 else if (s->cli_addr.ss_family == AF_INET) {
3214 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
3215 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
3216 sn, sizeof(sn)) &&
3217 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3218 pn, sizeof(pn))) {
3219 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3220 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
3221 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
3222 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3223 }
3224 }
3225 else {
3226 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
3227 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
3228 sn, sizeof(sn)) &&
3229 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
3230 pn, sizeof(pn))) {
3231 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3232 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
3233 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
3234 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3235 }
3236 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003237 }
willy tarreau0f7af912005-12-17 12:21:26 +01003238
willy tarreau982249e2005-12-18 00:57:06 +01003239 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01003240 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003241 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01003242 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01003243 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003244 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003245 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01003246 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01003247
willy tarreau8a86dbf2005-12-18 00:45:59 +01003248 if (s->cli_addr.ss_family == AF_INET) {
3249 char pn[INET_ADDRSTRLEN];
3250 inet_ntop(AF_INET,
3251 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3252 pn, sizeof(pn));
3253
3254 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3255 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3256 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
3257 }
3258 else {
3259 char pn[INET6_ADDRSTRLEN];
3260 inet_ntop(AF_INET6,
3261 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3262 pn, sizeof(pn));
3263
3264 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3265 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3266 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3267 }
3268
willy tarreauef900ab2005-12-17 12:52:52 +01003269 write(1, trash, len);
3270 }
willy tarreau0f7af912005-12-17 12:21:26 +01003271
willy tarreau5cbea6f2005-12-17 12:48:26 +01003272 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003273 if (s->rsp_cap != NULL)
3274 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3275 if (s->req_cap != NULL)
3276 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003277 close(cfd); /* nothing can be done for this fd without memory */
3278 pool_free(task, t);
3279 pool_free(session, s);
3280 return 0;
3281 }
willy tarreau4302f492005-12-18 01:00:37 +01003282
willy tarreau5cbea6f2005-12-17 12:48:26 +01003283 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003284 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003285 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3286 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003287 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003288 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003289
willy tarreau5cbea6f2005-12-17 12:48:26 +01003290 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3291 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003292 if (s->rsp_cap != NULL)
3293 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3294 if (s->req_cap != NULL)
3295 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003296 close(cfd); /* nothing can be done for this fd without memory */
3297 pool_free(task, t);
3298 pool_free(session, s);
3299 return 0;
3300 }
3301 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003302 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003303 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 +01003304
willy tarreau5cbea6f2005-12-17 12:48:26 +01003305 fdtab[cfd].read = &event_cli_read;
3306 fdtab[cfd].write = &event_cli_write;
3307 fdtab[cfd].owner = t;
3308 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003309
willy tarreaub1285d52005-12-18 01:20:14 +01003310 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3311 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3312 /* Either we got a request from a monitoring system on an HTTP instance,
3313 * or we're in health check mode with the 'httpchk' option enabled. In
3314 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3315 */
3316 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3317 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3318 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003319 }
3320 else {
3321 FD_SET(cfd, StaticReadEvent);
3322 }
3323
willy tarreaub952e1d2005-12-18 01:31:20 +01003324#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3325 if (PrevReadEvent) {
3326 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3327 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3328 }
3329#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003330 fd_insert(cfd);
3331
3332 tv_eternity(&s->cnexpire);
3333 tv_eternity(&s->srexpire);
3334 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003335 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003336 tv_eternity(&s->cwexpire);
3337
willy tarreaub1285d52005-12-18 01:20:14 +01003338 if (s->proxy->clitimeout) {
3339 if (FD_ISSET(cfd, StaticReadEvent))
3340 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3341 if (FD_ISSET(cfd, StaticWriteEvent))
3342 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3343 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003344
willy tarreaub1285d52005-12-18 01:20:14 +01003345 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003346
3347 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003348
3349 if (p->mode != PR_MODE_HEALTH)
3350 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003351
3352 p->nbconn++;
3353 actconn++;
3354 totalconn++;
3355
willy tarreaub952e1d2005-12-18 01:31:20 +01003356 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003357 } /* end of while (p->nbconn < p->maxconn) */
3358 return 0;
3359}
willy tarreau0f7af912005-12-17 12:21:26 +01003360
willy tarreau0f7af912005-12-17 12:21:26 +01003361
willy tarreau5cbea6f2005-12-17 12:48:26 +01003362/*
3363 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003364 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3365 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003366 * or -1 if an error occured.
3367 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003368int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003369 struct task *t = fdtab[fd].owner;
3370 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003371 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003372 socklen_t lskerr = sizeof(skerr);
3373
willy tarreau05be12b2006-03-19 19:35:00 +01003374 skerr = 1;
3375 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3376 || (skerr != 0)) {
3377 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003378 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003379 fdtab[fd].state = FD_STERROR;
3380 FD_CLR(fd, StaticWriteEvent);
3381 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003382 else if (s->result != -1) {
3383 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003384 if (s->proxy->options & PR_O_HTTP_CHK) {
3385 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003386 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003387 * so we'll send the request, and won't wake the checker up now.
3388 */
3389#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003390 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003391#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003392 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003393#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003394 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003395 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3396 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3397 return 0;
3398 }
willy tarreau05be12b2006-03-19 19:35:00 +01003399 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003400 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003401 FD_CLR(fd, StaticWriteEvent);
3402 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003403 }
3404 else {
3405 /* good TCP connection is enough */
3406 s->result = 1;
3407 }
3408 }
3409
3410 task_wakeup(&rq, t);
3411 return 0;
3412}
3413
willy tarreau0f7af912005-12-17 12:21:26 +01003414
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003415/*
3416 * This function is used only for server health-checks. It handles
3417 * the server's reply to an HTTP request. It returns 1 if the server replies
3418 * 2xx or 3xx (valid responses), or -1 in other cases.
3419 */
3420int event_srv_chk_r(int fd) {
3421 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003422 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003423 struct task *t = fdtab[fd].owner;
3424 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003425 int skerr;
3426 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003427
willy tarreaua4a583a2005-12-18 01:39:19 +01003428 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003429
willy tarreau05be12b2006-03-19 19:35:00 +01003430 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3431 if (!skerr) {
3432#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003433 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003434#else
willy tarreau05be12b2006-03-19 19:35:00 +01003435 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3436 * but the connection was closed on the remote end. Fortunately, recv still
3437 * works correctly and we don't need to do the getsockopt() on linux.
3438 */
3439 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003440#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003441
3442 if ((len >= sizeof("HTTP/1.0 000")) &&
3443 !memcmp(reply, "HTTP/1.", 7) &&
3444 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3445 result = 1;
3446 }
3447
3448 if (result == -1)
3449 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003450
3451 if (s->result != -1)
3452 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003453
3454 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003455 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003456 return 0;
3457}
3458
3459
3460/*
3461 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3462 * and moves <end> just after the end of <str>.
3463 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3464 * the shift value (positive or negative) is returned.
3465 * If there's no space left, the move is not done.
3466 *
3467 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003468int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003469 int delta;
3470 int len;
3471
3472 len = strlen(str);
3473 delta = len - (end - pos);
3474
3475 if (delta + b->r >= b->data + BUFSIZE)
3476 return 0; /* no space left */
3477
3478 /* first, protect the end of the buffer */
3479 memmove(end + delta, end, b->data + b->l - end);
3480
3481 /* now, copy str over pos */
3482 memcpy(pos, str,len);
3483
willy tarreau5cbea6f2005-12-17 12:48:26 +01003484 /* we only move data after the displaced zone */
3485 if (b->r > pos) b->r += delta;
3486 if (b->w > pos) b->w += delta;
3487 if (b->h > pos) b->h += delta;
3488 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003489 b->l += delta;
3490
3491 return delta;
3492}
3493
willy tarreau8337c6b2005-12-17 13:41:01 +01003494/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003495 * len is 0.
3496 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003497int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003498 int delta;
3499
3500 delta = len - (end - pos);
3501
3502 if (delta + b->r >= b->data + BUFSIZE)
3503 return 0; /* no space left */
3504
Willy TARREAUe78ae262006-01-08 01:24:12 +01003505 if (b->data + b->l < end)
3506 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3507 return 0;
3508
willy tarreau0f7af912005-12-17 12:21:26 +01003509 /* first, protect the end of the buffer */
3510 memmove(end + delta, end, b->data + b->l - end);
3511
3512 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003513 if (len)
3514 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003515
willy tarreau5cbea6f2005-12-17 12:48:26 +01003516 /* we only move data after the displaced zone */
3517 if (b->r > pos) b->r += delta;
3518 if (b->w > pos) b->w += delta;
3519 if (b->h > pos) b->h += delta;
3520 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003521 b->l += delta;
3522
3523 return delta;
3524}
3525
3526
3527int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3528 char *old_dst = dst;
3529
3530 while (*str) {
3531 if (*str == '\\') {
3532 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003533 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003534 int len, num;
3535
3536 num = *str - '0';
3537 str++;
3538
willy tarreau8a86dbf2005-12-18 00:45:59 +01003539 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003540 len = matches[num].rm_eo - matches[num].rm_so;
3541 memcpy(dst, src + matches[num].rm_so, len);
3542 dst += len;
3543 }
3544
3545 }
3546 else if (*str == 'x') {
3547 unsigned char hex1, hex2;
3548 str++;
3549
willy tarreauc1f47532005-12-18 01:08:26 +01003550 hex1 = toupper(*str++) - '0';
3551 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003552
3553 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3554 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3555 *dst++ = (hex1<<4) + hex2;
3556 }
3557 else
3558 *dst++ = *str++;
3559 }
3560 else
3561 *dst++ = *str++;
3562 }
3563 *dst = 0;
3564 return dst - old_dst;
3565}
3566
willy tarreauc1f47532005-12-18 01:08:26 +01003567static int ishex(char s)
3568{
3569 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3570}
3571
3572/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3573char *check_replace_string(char *str)
3574{
3575 char *err = NULL;
3576 while (*str) {
3577 if (*str == '\\') {
3578 err = str; /* in case of a backslash, we return the pointer to it */
3579 str++;
3580 if (!*str)
3581 return err;
3582 else if (isdigit((int)*str))
3583 err = NULL;
3584 else if (*str == 'x') {
3585 str++;
3586 if (!ishex(*str))
3587 return err;
3588 str++;
3589 if (!ishex(*str))
3590 return err;
3591 err = NULL;
3592 }
3593 else {
3594 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3595 err = NULL;
3596 }
3597 }
3598 str++;
3599 }
3600 return err;
3601}
3602
3603
willy tarreau9fe663a2005-12-17 13:02:59 +01003604
willy tarreau0f7af912005-12-17 12:21:26 +01003605/*
3606 * manages the client FSM and its socket. BTW, it also tries to handle the
3607 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3608 * 0 else.
3609 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003610int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003611 int s = t->srv_state;
3612 int c = t->cli_state;
3613 struct buffer *req = t->req;
3614 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003615 int method_checked = 0;
3616 appsess *asession_temp = NULL;
3617 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003618
willy tarreau750a4722005-12-17 13:21:24 +01003619#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003620 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3621 cli_stnames[c], srv_stnames[s],
3622 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3623 t->crexpire.tv_sec, t->crexpire.tv_usec,
3624 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003625#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003626 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3627 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3628 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3629 //);
3630 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003631 /* now parse the partial (or complete) headers */
3632 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3633 char *ptr;
3634 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003635 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003636
willy tarreau5cbea6f2005-12-17 12:48:26 +01003637 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003638
willy tarreau0f7af912005-12-17 12:21:26 +01003639 /* look for the end of the current header */
3640 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3641 ptr++;
3642
willy tarreau5cbea6f2005-12-17 12:48:26 +01003643 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003644 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02003645
3646 /*
3647 * first, let's check that it's not a leading empty line, in
3648 * which case we'll ignore and remove it (according to RFC2616).
3649 */
3650 if (req->h == req->data) {
3651 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3652 if (ptr > req->r - 2) {
3653 /* this is a partial header, let's wait for more to come */
3654 req->lr = ptr;
3655 break;
3656 }
3657
3658 /* now we know that *ptr is either \r or \n,
3659 * and that there are at least 1 char after it.
3660 */
3661 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3662 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3663 else
3664 req->lr = ptr + 2; /* \r\n or \n\r */
3665 /* ignore empty leading lines */
3666 buffer_replace2(req, req->h, req->lr, NULL, 0);
3667 req->h = req->lr;
3668 continue;
3669 }
3670
willy tarreau5cbea6f2005-12-17 12:48:26 +01003671 /* we can only get here after an end of headers */
3672 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003673
willy tarreaue39cd132005-12-17 13:00:18 +01003674 if (t->flags & SN_CLDENY) {
3675 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003676 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003677 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003678 if (!(t->flags & SN_ERR_MASK))
3679 t->flags |= SN_ERR_PRXCOND;
3680 if (!(t->flags & SN_FINST_MASK))
3681 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003682 return 1;
3683 }
3684
willy tarreau5cbea6f2005-12-17 12:48:26 +01003685 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003686 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3687 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003688 }
willy tarreau0f7af912005-12-17 12:21:26 +01003689
willy tarreau9fe663a2005-12-17 13:02:59 +01003690 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003691 if (t->cli_addr.ss_family == AF_INET) {
3692 unsigned char *pn;
3693 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3694 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3695 pn[0], pn[1], pn[2], pn[3]);
3696 buffer_replace2(req, req->h, req->h, trash, len);
3697 }
3698 else if (t->cli_addr.ss_family == AF_INET6) {
3699 char pn[INET6_ADDRSTRLEN];
3700 inet_ntop(AF_INET6,
3701 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3702 pn, sizeof(pn));
3703 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3704 buffer_replace2(req, req->h, req->h, trash, len);
3705 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003706 }
3707
willy tarreau25c4ea52005-12-18 00:49:49 +01003708 /* add a "connection: close" line if needed */
3709 if (t->proxy->options & PR_O_HTTP_CLOSE)
3710 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3711
willy tarreau982249e2005-12-18 00:57:06 +01003712 if (!memcmp(req->data, "POST ", 5)) {
3713 /* this is a POST request, which is not cacheable by default */
3714 t->flags |= SN_POST;
3715 }
willy tarreaucd878942005-12-17 13:27:43 +01003716
willy tarreau5cbea6f2005-12-17 12:48:26 +01003717 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003718 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003719
willy tarreau750a4722005-12-17 13:21:24 +01003720 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003721 /* FIXME: we'll set the client in a wait state while we try to
3722 * connect to the server. Is this really needed ? wouldn't it be
willy tarreau0889c962006-04-24 14:36:48 +02003723 * better to release the maximum of system buffers instead ?
3724 * The solution is to enable the FD but set its time-out to
3725 * eternity as long as the server-side does not enable data xfer.
3726 * CL_STDATA also has to take care of this, which is done below.
3727 */
willy tarreauef900ab2005-12-17 12:52:52 +01003728 //FD_CLR(t->cli_fd, StaticReadEvent);
3729 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003730
3731 /* FIXME: if we break here (as up to 1.1.23), having the client
3732 * shutdown its connection can lead to an abort further.
3733 * it's better to either return 1 or even jump directly to the
3734 * data state which will save one schedule.
3735 */
3736 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003737
3738 if (!t->proxy->clitimeout ||
3739 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3740 /* If the client has no timeout, or if the server is not ready yet,
3741 * and we know for sure that it can expire, then it's cleaner to
3742 * disable the timeout on the client side so that too low values
3743 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003744 *
3745 * FIXME-20050705: the server needs a way to re-enable this time-out
3746 * when it switches its state, otherwise a client can stay connected
3747 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003748 */
3749 tv_eternity(&t->crexpire);
3750
willy tarreau197e8ec2005-12-17 14:10:59 +01003751 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003752 }
willy tarreau0f7af912005-12-17 12:21:26 +01003753
Willy TARREAU13032e72006-03-12 17:31:45 +01003754 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3755 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003756 /* this is a partial header, let's wait for more to come */
3757 req->lr = ptr;
3758 break;
3759 }
willy tarreau0f7af912005-12-17 12:21:26 +01003760
willy tarreau5cbea6f2005-12-17 12:48:26 +01003761 /* now we know that *ptr is either \r or \n,
3762 * and that there are at least 1 char after it.
3763 */
3764 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3765 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3766 else
3767 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003768
willy tarreau5cbea6f2005-12-17 12:48:26 +01003769 /*
3770 * now we know that we have a full header ; we can do whatever
3771 * we want with these pointers :
3772 * req->h = beginning of header
3773 * ptr = end of header (first \r or \n)
3774 * req->lr = beginning of next line (next rep->h)
3775 * req->r = end of data (not used at this stage)
3776 */
willy tarreau0f7af912005-12-17 12:21:26 +01003777
willy tarreau12350152005-12-18 01:03:27 +01003778 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3779 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3780 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3781
3782 /* skip ; */
3783 request_line++;
3784
3785 /* look if we have a jsessionid */
3786
3787 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3788
3789 /* skip jsessionid= */
3790 request_line += t->proxy->appsession_name_len + 1;
3791
3792 /* First try if we allready have an appsession */
3793 asession_temp = &local_asession;
3794
3795 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3796 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3797 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3798 return 0;
3799 }
3800
3801 /* Copy the sessionid */
3802 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3803 asession_temp->sessid[t->proxy->appsession_len] = 0;
3804 asession_temp->serverid = NULL;
3805
3806 /* only do insert, if lookup fails */
3807 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3808 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3809 Alert("Not enough memory process_cli():asession:calloc().\n");
3810 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3811 return 0;
3812 }
3813 asession_temp->sessid = local_asession.sessid;
3814 asession_temp->serverid = local_asession.serverid;
3815 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003816 } /* end if (chtbl_lookup()) */
3817 else {
willy tarreau12350152005-12-18 01:03:27 +01003818 /*free wasted memory;*/
3819 pool_free_to(apools.sessid, local_asession.sessid);
3820 }
3821
3822 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3823 asession_temp->request_count++;
3824
3825#if defined(DEBUG_HASH)
3826 print_table(&(t->proxy->htbl_proxy));
3827#endif
3828
3829 if (asession_temp->serverid == NULL) {
3830 Alert("Found Application Session without matching server.\n");
3831 } else {
3832 struct server *srv = t->proxy->srv;
3833 while (srv) {
3834 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3835 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3836 /* we found the server and it's usable */
3837 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02003838 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01003839 t->srv = srv;
3840 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003841 } else {
willy tarreau12350152005-12-18 01:03:27 +01003842 t->flags &= ~SN_CK_MASK;
3843 t->flags |= SN_CK_DOWN;
3844 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003845 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003846 srv = srv->next;
3847 }/* end while(srv) */
3848 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003849 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003850 else {
3851 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3852 }
willy tarreau598da412005-12-18 01:07:29 +01003853 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003854 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003855 else{
3856 //printf("No Methode-Header with Session-String\n");
3857 }
3858
willy tarreau8337c6b2005-12-17 13:41:01 +01003859 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003860 /* we have a complete HTTP request that we must log */
3861 int urilen;
3862
willy tarreaua1598082005-12-17 13:08:06 +01003863 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003864 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003865 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003866 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003867 if (!(t->flags & SN_ERR_MASK))
3868 t->flags |= SN_ERR_PRXCOND;
3869 if (!(t->flags & SN_FINST_MASK))
3870 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003871 return 1;
3872 }
3873
3874 urilen = ptr - req->h;
3875 if (urilen >= REQURI_LEN)
3876 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003877 memcpy(t->logs.uri, req->h, urilen);
3878 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003879
willy tarreaua1598082005-12-17 13:08:06 +01003880 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003881 sess_log(t);
3882 }
willy tarreau4302f492005-12-18 01:00:37 +01003883 else if (t->logs.logwait & LW_REQHDR) {
3884 struct cap_hdr *h;
3885 int len;
3886 for (h = t->proxy->req_cap; h; h = h->next) {
3887 if ((h->namelen + 2 <= ptr - req->h) &&
3888 (req->h[h->namelen] == ':') &&
3889 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3890
3891 if (t->req_cap[h->index] == NULL)
3892 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3893
3894 len = ptr - (req->h + h->namelen + 2);
3895 if (len > h->len)
3896 len = h->len;
3897
3898 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3899 t->req_cap[h->index][len]=0;
3900 }
3901 }
3902
3903 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003904
willy tarreau5cbea6f2005-12-17 12:48:26 +01003905 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003906
willy tarreau982249e2005-12-18 00:57:06 +01003907 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003908 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003909 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 +01003910 max = ptr - req->h;
3911 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003912 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003913 trash[len++] = '\n';
3914 write(1, trash, len);
3915 }
willy tarreau0f7af912005-12-17 12:21:26 +01003916
willy tarreau25c4ea52005-12-18 00:49:49 +01003917
3918 /* remove "connection: " if needed */
3919 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3920 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3921 delete_header = 1;
3922 }
3923
willy tarreau5cbea6f2005-12-17 12:48:26 +01003924 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003925 if (!delete_header && t->proxy->req_exp != NULL
3926 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003927 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003928 char term;
3929
3930 term = *ptr;
3931 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003932 exp = t->proxy->req_exp;
3933 do {
3934 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3935 switch (exp->action) {
3936 case ACT_ALLOW:
3937 if (!(t->flags & SN_CLDENY))
3938 t->flags |= SN_CLALLOW;
3939 break;
3940 case ACT_REPLACE:
3941 if (!(t->flags & SN_CLDENY)) {
3942 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3943 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3944 }
3945 break;
3946 case ACT_REMOVE:
3947 if (!(t->flags & SN_CLDENY))
3948 delete_header = 1;
3949 break;
3950 case ACT_DENY:
3951 if (!(t->flags & SN_CLALLOW))
3952 t->flags |= SN_CLDENY;
3953 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003954 case ACT_PASS: /* we simply don't deny this one */
3955 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003956 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003957 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003958 }
willy tarreaue39cd132005-12-17 13:00:18 +01003959 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003960 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003961 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003962
willy tarreau240afa62005-12-17 13:14:35 +01003963 /* Now look for cookies. Conforming to RFC2109, we have to support
3964 * attributes whose name begin with a '$', and associate them with
3965 * the right cookie, if we want to delete this cookie.
3966 * So there are 3 cases for each cookie read :
3967 * 1) it's a special attribute, beginning with a '$' : ignore it.
3968 * 2) it's a server id cookie that we *MAY* want to delete : save
3969 * some pointers on it (last semi-colon, beginning of cookie...)
3970 * 3) it's an application cookie : we *MAY* have to delete a previous
3971 * "special" cookie.
3972 * At the end of loop, if a "special" cookie remains, we may have to
3973 * remove it. If no application cookie persists in the header, we
3974 * *MUST* delete it
3975 */
willy tarreau12350152005-12-18 01:03:27 +01003976 if (!delete_header &&
3977 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003978 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003979 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003980 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003981 char *del_colon, *del_cookie, *colon;
3982 int app_cookies;
3983
willy tarreau5cbea6f2005-12-17 12:48:26 +01003984 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003985 colon = p1;
3986 /* del_cookie == NULL => nothing to be deleted */
3987 del_colon = del_cookie = NULL;
3988 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003989
3990 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003991 /* skip spaces and colons, but keep an eye on these ones */
3992 while (p1 < ptr) {
3993 if (*p1 == ';' || *p1 == ',')
3994 colon = p1;
3995 else if (!isspace((int)*p1))
3996 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003997 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003998 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003999
4000 if (p1 == ptr)
4001 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004002
4003 /* p1 is at the beginning of the cookie name */
4004 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01004005 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004006 p2++;
4007
4008 if (p2 == ptr)
4009 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004010
4011 p3 = p2 + 1; /* skips the '=' sign */
4012 if (p3 == ptr)
4013 break;
4014
willy tarreau240afa62005-12-17 13:14:35 +01004015 p4 = p3;
4016 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004017 p4++;
4018
4019 /* here, we have the cookie name between p1 and p2,
4020 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01004021 * we can process it :
4022 *
4023 * Cookie: NAME=VALUE;
4024 * | || || |
4025 * | || || +--> p4
4026 * | || |+-------> p3
4027 * | || +--------> p2
4028 * | |+------------> p1
4029 * | +-------------> colon
4030 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01004031 */
4032
willy tarreau240afa62005-12-17 13:14:35 +01004033 if (*p1 == '$') {
4034 /* skip this one */
4035 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004036 else {
4037 /* first, let's see if we want to capture it */
4038 if (t->proxy->capture_name != NULL &&
4039 t->logs.cli_cookie == NULL &&
4040 (p4 - p1 >= t->proxy->capture_namelen) &&
4041 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4042 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004043
willy tarreau8337c6b2005-12-17 13:41:01 +01004044 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4045 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01004046 } else {
4047 if (log_len > t->proxy->capture_len)
4048 log_len = t->proxy->capture_len;
4049 memcpy(t->logs.cli_cookie, p1, log_len);
4050 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01004051 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004052 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004053
4054 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4055 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
4056 /* Cool... it's the right one */
4057 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01004058 char *delim;
4059
4060 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4061 * have the server ID betweek p3 and delim, and the original cookie between
4062 * delim+1 and p4. Otherwise, delim==p4 :
4063 *
4064 * Cookie: NAME=SRV~VALUE;
4065 * | || || | |
4066 * | || || | +--> p4
4067 * | || || +--------> delim
4068 * | || |+-----------> p3
4069 * | || +------------> p2
4070 * | |+----------------> p1
4071 * | +-----------------> colon
4072 * +------------------------> req->h
4073 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004074
willy tarreau0174f312005-12-18 01:02:42 +01004075 if (t->proxy->options & PR_O_COOK_PFX) {
4076 for (delim = p3; delim < p4; delim++)
4077 if (*delim == COOKIE_DELIM)
4078 break;
4079 }
4080 else
4081 delim = p4;
4082
4083
4084 /* Here, we'll look for the first running server which supports the cookie.
4085 * This allows to share a same cookie between several servers, for example
4086 * to dedicate backup servers to specific servers only.
willy tarreau422bb2e2006-05-10 04:27:21 +02004087 * However, to prevent clients from sticking to cookie-less backup server
4088 * when they have incidentely learned an empty cookie, we simply ignore
4089 * empty cookies and mark them as invalid.
willy tarreau0174f312005-12-18 01:02:42 +01004090 */
willy tarreau422bb2e2006-05-10 04:27:21 +02004091 if (delim == p3)
4092 srv = NULL;
4093
willy tarreau0174f312005-12-18 01:02:42 +01004094 while (srv) {
4095 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
4096 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4097 /* we found the server and it's usable */
4098 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004099 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau0174f312005-12-18 01:02:42 +01004100 t->srv = srv;
4101 break;
willy tarreau12350152005-12-18 01:03:27 +01004102 } else {
willy tarreau0174f312005-12-18 01:02:42 +01004103 /* we found a server, but it's down */
4104 t->flags &= ~SN_CK_MASK;
4105 t->flags |= SN_CK_DOWN;
4106 }
4107 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004108 srv = srv->next;
4109 }
4110
willy tarreau0174f312005-12-18 01:02:42 +01004111 if (!srv && !(t->flags & SN_CK_DOWN)) {
4112 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01004113 t->flags &= ~SN_CK_MASK;
4114 t->flags |= SN_CK_INVALID;
4115 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004116
willy tarreau0174f312005-12-18 01:02:42 +01004117 /* depending on the cookie mode, we may have to either :
4118 * - delete the complete cookie if we're in insert+indirect mode, so that
4119 * the server never sees it ;
4120 * - remove the server id from the cookie value, and tag the cookie as an
4121 * application cookie so that it does not get accidentely removed later,
4122 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01004123 */
willy tarreau0174f312005-12-18 01:02:42 +01004124 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
4125 buffer_replace2(req, p3, delim + 1, NULL, 0);
4126 p4 -= (delim + 1 - p3);
4127 ptr -= (delim + 1 - p3);
4128 del_cookie = del_colon = NULL;
4129 app_cookies++; /* protect the header from deletion */
4130 }
4131 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01004132 (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 +01004133 del_cookie = p1;
4134 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01004135 }
willy tarreau12350152005-12-18 01:03:27 +01004136 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01004137 /* now we know that we must keep this cookie since it's
4138 * not ours. But if we wanted to delete our cookie
4139 * earlier, we cannot remove the complete header, but we
4140 * can remove the previous block itself.
4141 */
4142 app_cookies++;
4143
4144 if (del_cookie != NULL) {
4145 buffer_replace2(req, del_cookie, p1, NULL, 0);
4146 p4 -= (p1 - del_cookie);
4147 ptr -= (p1 - del_cookie);
4148 del_cookie = del_colon = NULL;
4149 }
willy tarreau240afa62005-12-17 13:14:35 +01004150 }
willy tarreau12350152005-12-18 01:03:27 +01004151
4152 if ((t->proxy->appsession_name != NULL) &&
4153 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4154 /* first, let's see if the cookie is our appcookie*/
4155
4156 /* Cool... it's the right one */
4157
4158 asession_temp = &local_asession;
4159
4160 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4161 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4162 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4163 return 0;
4164 }
4165
4166 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4167 asession_temp->sessid[t->proxy->appsession_len] = 0;
4168 asession_temp->serverid = NULL;
4169
4170 /* only do insert, if lookup fails */
4171 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4172 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4173 Alert("Not enough memory process_cli():asession:calloc().\n");
4174 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4175 return 0;
4176 }
4177
4178 asession_temp->sessid = local_asession.sessid;
4179 asession_temp->serverid = local_asession.serverid;
4180 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4181 }
4182 else{
4183 /* free wasted memory */
4184 pool_free_to(apools.sessid, local_asession.sessid);
4185 }
4186
4187 if (asession_temp->serverid == NULL) {
4188 Alert("Found Application Session without matching server.\n");
4189 } else {
4190 struct server *srv = t->proxy->srv;
4191 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01004192 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01004193 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4194 /* we found the server and it's usable */
4195 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004196 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004197 t->srv = srv;
4198 break;
4199 } else {
4200 t->flags &= ~SN_CK_MASK;
4201 t->flags |= SN_CK_DOWN;
4202 }
4203 }
4204 srv = srv->next;
4205 }/* end while(srv) */
4206 }/* end else if server == NULL */
4207
4208 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01004209 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004210 }
willy tarreau240afa62005-12-17 13:14:35 +01004211
willy tarreau5cbea6f2005-12-17 12:48:26 +01004212 /* we'll have to look for another cookie ... */
4213 p1 = p4;
4214 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01004215
4216 /* There's no more cookie on this line.
4217 * We may have marked the last one(s) for deletion.
4218 * We must do this now in two ways :
4219 * - if there is no app cookie, we simply delete the header ;
4220 * - if there are app cookies, we must delete the end of the
4221 * string properly, including the colon/semi-colon before
4222 * the cookie name.
4223 */
4224 if (del_cookie != NULL) {
4225 if (app_cookies) {
4226 buffer_replace2(req, del_colon, ptr, NULL, 0);
4227 /* WARNING! <ptr> becomes invalid for now. If some code
4228 * below needs to rely on it before the end of the global
4229 * header loop, we need to correct it with this code :
4230 * ptr = del_colon;
4231 */
4232 }
4233 else
4234 delete_header = 1;
4235 }
4236 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004237
4238 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004239 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01004240 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01004241 }
willy tarreau240afa62005-12-17 13:14:35 +01004242 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
4243
willy tarreau5cbea6f2005-12-17 12:48:26 +01004244 req->h = req->lr;
4245 } /* while (req->lr < req->r) */
4246
4247 /* end of header processing (even if incomplete) */
4248
willy tarreauef900ab2005-12-17 12:52:52 +01004249 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4250 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4251 * full. We cannot loop here since event_cli_read will disable it only if
4252 * req->l == rlim-data
4253 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004254 FD_SET(t->cli_fd, StaticReadEvent);
4255 if (t->proxy->clitimeout)
4256 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4257 else
4258 tv_eternity(&t->crexpire);
4259 }
4260
willy tarreaue39cd132005-12-17 13:00:18 +01004261 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01004262 * won't be able to free more later, so the session will never terminate.
4263 */
willy tarreaue39cd132005-12-17 13:00:18 +01004264 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01004265 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01004266 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01004267 if (!(t->flags & SN_ERR_MASK))
4268 t->flags |= SN_ERR_PRXCOND;
4269 if (!(t->flags & SN_FINST_MASK))
4270 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004271 return 1;
4272 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004273 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004274 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004275 tv_eternity(&t->crexpire);
4276 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004277 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004278 if (!(t->flags & SN_ERR_MASK))
4279 t->flags |= SN_ERR_CLICL;
4280 if (!(t->flags & SN_FINST_MASK))
4281 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004282 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004283 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004284 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4285
4286 /* read timeout : give up with an error message.
4287 */
4288 t->logs.status = 408;
4289 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004290 if (!(t->flags & SN_ERR_MASK))
4291 t->flags |= SN_ERR_CLITO;
4292 if (!(t->flags & SN_FINST_MASK))
4293 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004294 return 1;
4295 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004296
4297 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004298 }
4299 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004300 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004301 /* FIXME: this error handling is partly buggy because we always report
4302 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4303 * or HEADER phase. BTW, it's not logical to expire the client while
4304 * we're waiting for the server to connect.
4305 */
willy tarreau0f7af912005-12-17 12:21:26 +01004306 /* read or write error */
4307 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004308 tv_eternity(&t->crexpire);
4309 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004310 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004311 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004312 if (!(t->flags & SN_ERR_MASK))
4313 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004314 if (!(t->flags & SN_FINST_MASK)) {
4315 if (t->pend_pos)
4316 t->flags |= SN_FINST_Q;
4317 else if (s == SV_STCONN)
4318 t->flags |= SN_FINST_C;
4319 else
4320 t->flags |= SN_FINST_D;
4321 }
willy tarreau0f7af912005-12-17 12:21:26 +01004322 return 1;
4323 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004324 /* last read, or end of server write */
4325 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004326 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004327 tv_eternity(&t->crexpire);
4328 shutdown(t->cli_fd, SHUT_RD);
4329 t->cli_state = CL_STSHUTR;
4330 return 1;
4331 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004332 /* last server read and buffer empty */
4333 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004334 FD_CLR(t->cli_fd, StaticWriteEvent);
4335 tv_eternity(&t->cwexpire);
4336 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004337 /* We must ensure that the read part is still alive when switching
4338 * to shutw */
4339 FD_SET(t->cli_fd, StaticReadEvent);
4340 if (t->proxy->clitimeout)
4341 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004342 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004343 //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 +01004344 return 1;
4345 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004346 /* read timeout */
4347 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4348 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004349 tv_eternity(&t->crexpire);
4350 shutdown(t->cli_fd, SHUT_RD);
4351 t->cli_state = CL_STSHUTR;
4352 if (!(t->flags & SN_ERR_MASK))
4353 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004354 if (!(t->flags & SN_FINST_MASK)) {
4355 if (t->pend_pos)
4356 t->flags |= SN_FINST_Q;
4357 else if (s == SV_STCONN)
4358 t->flags |= SN_FINST_C;
4359 else
4360 t->flags |= SN_FINST_D;
4361 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004362 return 1;
4363 }
4364 /* write timeout */
4365 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4366 FD_CLR(t->cli_fd, StaticWriteEvent);
4367 tv_eternity(&t->cwexpire);
4368 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004369 /* We must ensure that the read part is still alive when switching
4370 * to shutw */
4371 FD_SET(t->cli_fd, StaticReadEvent);
4372 if (t->proxy->clitimeout)
4373 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4374
willy tarreau036e1ce2005-12-17 13:46:33 +01004375 t->cli_state = CL_STSHUTW;
4376 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004377 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004378 if (!(t->flags & SN_FINST_MASK)) {
4379 if (t->pend_pos)
4380 t->flags |= SN_FINST_Q;
4381 else if (s == SV_STCONN)
4382 t->flags |= SN_FINST_C;
4383 else
4384 t->flags |= SN_FINST_D;
4385 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004386 return 1;
4387 }
willy tarreau0f7af912005-12-17 12:21:26 +01004388
willy tarreauc58fc692005-12-17 14:13:08 +01004389 if (req->l >= req->rlim - req->data) {
4390 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004391 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004392 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004393 FD_CLR(t->cli_fd, StaticReadEvent);
4394 tv_eternity(&t->crexpire);
4395 }
4396 }
4397 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004398 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004399 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4400 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004401 if (!t->proxy->clitimeout ||
4402 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4403 /* If the client has no timeout, or if the server not ready yet, and we
4404 * know for sure that it can expire, then it's cleaner to disable the
4405 * timeout on the client side so that too low values cannot make the
4406 * sessions abort too early.
4407 */
willy tarreau0f7af912005-12-17 12:21:26 +01004408 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004409 else
4410 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004411 }
4412 }
4413
4414 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004415 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004416 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4417 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4418 tv_eternity(&t->cwexpire);
4419 }
4420 }
4421 else { /* buffer not empty */
4422 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4423 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004424 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004425 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004426 /* FIXME: to prevent the client from expiring read timeouts during writes,
4427 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004428 t->crexpire = t->cwexpire;
4429 }
willy tarreau0f7af912005-12-17 12:21:26 +01004430 else
4431 tv_eternity(&t->cwexpire);
4432 }
4433 }
4434 return 0; /* other cases change nothing */
4435 }
4436 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004437 if (t->res_cw == RES_ERROR) {
4438 tv_eternity(&t->cwexpire);
4439 fd_delete(t->cli_fd);
4440 t->cli_state = CL_STCLOSE;
4441 if (!(t->flags & SN_ERR_MASK))
4442 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004443 if (!(t->flags & SN_FINST_MASK)) {
4444 if (t->pend_pos)
4445 t->flags |= SN_FINST_Q;
4446 else if (s == SV_STCONN)
4447 t->flags |= SN_FINST_C;
4448 else
4449 t->flags |= SN_FINST_D;
4450 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004451 return 1;
4452 }
4453 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004454 tv_eternity(&t->cwexpire);
4455 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004456 t->cli_state = CL_STCLOSE;
4457 return 1;
4458 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004459 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4460 tv_eternity(&t->cwexpire);
4461 fd_delete(t->cli_fd);
4462 t->cli_state = CL_STCLOSE;
4463 if (!(t->flags & SN_ERR_MASK))
4464 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004465 if (!(t->flags & SN_FINST_MASK)) {
4466 if (t->pend_pos)
4467 t->flags |= SN_FINST_Q;
4468 else if (s == SV_STCONN)
4469 t->flags |= SN_FINST_C;
4470 else
4471 t->flags |= SN_FINST_D;
4472 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004473 return 1;
4474 }
willy tarreau0f7af912005-12-17 12:21:26 +01004475 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004476 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004477 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4478 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4479 tv_eternity(&t->cwexpire);
4480 }
4481 }
4482 else { /* buffer not empty */
4483 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4484 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004485 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004486 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004487 /* FIXME: to prevent the client from expiring read timeouts during writes,
4488 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004489 t->crexpire = t->cwexpire;
4490 }
willy tarreau0f7af912005-12-17 12:21:26 +01004491 else
4492 tv_eternity(&t->cwexpire);
4493 }
4494 }
4495 return 0;
4496 }
4497 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004498 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004499 tv_eternity(&t->crexpire);
4500 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004501 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004502 if (!(t->flags & SN_ERR_MASK))
4503 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004504 if (!(t->flags & SN_FINST_MASK)) {
4505 if (t->pend_pos)
4506 t->flags |= SN_FINST_Q;
4507 else if (s == SV_STCONN)
4508 t->flags |= SN_FINST_C;
4509 else
4510 t->flags |= SN_FINST_D;
4511 }
willy tarreau0f7af912005-12-17 12:21:26 +01004512 return 1;
4513 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004514 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4515 tv_eternity(&t->crexpire);
4516 fd_delete(t->cli_fd);
4517 t->cli_state = CL_STCLOSE;
4518 return 1;
4519 }
4520 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4521 tv_eternity(&t->crexpire);
4522 fd_delete(t->cli_fd);
4523 t->cli_state = CL_STCLOSE;
4524 if (!(t->flags & SN_ERR_MASK))
4525 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004526 if (!(t->flags & SN_FINST_MASK)) {
4527 if (t->pend_pos)
4528 t->flags |= SN_FINST_Q;
4529 else if (s == SV_STCONN)
4530 t->flags |= SN_FINST_C;
4531 else
4532 t->flags |= SN_FINST_D;
4533 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004534 return 1;
4535 }
willy tarreauef900ab2005-12-17 12:52:52 +01004536 else if (req->l >= req->rlim - req->data) {
4537 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004538
4539 /* FIXME-20050705: is it possible for a client to maintain a session
4540 * after the timeout by sending more data after it receives a close ?
4541 */
4542
willy tarreau0f7af912005-12-17 12:21:26 +01004543 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004544 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004545 FD_CLR(t->cli_fd, StaticReadEvent);
4546 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004547 //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 +01004548 }
4549 }
4550 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004551 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004552 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4553 FD_SET(t->cli_fd, StaticReadEvent);
4554 if (t->proxy->clitimeout)
4555 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4556 else
4557 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004558 //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 +01004559 }
4560 }
4561 return 0;
4562 }
4563 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004564 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004565 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004566 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 +01004567 write(1, trash, len);
4568 }
4569 return 0;
4570 }
4571 return 0;
4572}
4573
willy tarreaudfece232006-05-02 00:19:57 +02004574/* This function turns the server state into the SV_STCLOSE, and sets
4575 * indicators accordingly. Note that if <status> is 0, no message is
4576 * returned.
4577 */
4578void srv_close_with_err(struct session *t, int err, int finst, int status, int msglen, char *msg) {
4579 t->srv_state = SV_STCLOSE;
4580 if (status > 0) {
4581 t->logs.status = status;
4582 if (t->proxy->mode == PR_MODE_HTTP)
4583 client_return(t, msglen, msg);
4584 }
4585 if (!(t->flags & SN_ERR_MASK))
4586 t->flags |= err;
4587 if (!(t->flags & SN_FINST_MASK))
4588 t->flags |= finst;
4589}
4590
4591/*
4592 * This function checks the retry count during the connect() job.
4593 * It updates the session's srv_state and retries, so that the caller knows
4594 * what it has to do. It uses the last connection error to set the log when
4595 * it expires. It returns 1 when it has expired, and 0 otherwise.
4596 */
4597int srv_count_retry_down(struct session *t, int conn_err) {
4598 /* we are in front of a retryable error */
4599 t->conn_retries--;
4600 if (t->conn_retries < 0) {
4601 /* if not retryable anymore, let's abort */
4602 tv_eternity(&t->cnexpire);
4603 srv_close_with_err(t, conn_err, SN_FINST_C,
4604 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4605
4606 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02004607 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02004608 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004609 if (may_dequeue_tasks(t->srv, t->proxy))
4610 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004611 return 1;
4612 }
4613 return 0;
4614}
willy tarreau0f7af912005-12-17 12:21:26 +01004615
4616/*
willy tarreaudfece232006-05-02 00:19:57 +02004617 * This function performs the retryable part of the connect() job.
4618 * It updates the session's srv_state and retries, so that the caller knows
4619 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
4620 * it needs to redispatch.
4621 */
4622int srv_retryable_connect(struct session *t) {
4623 int conn_err;
4624
4625 /* This loop ensures that we stop before the last retry in case of a
4626 * redispatchable server.
4627 */
4628 do {
4629 /* initiate a connection to the server */
4630 conn_err = connect_server(t);
4631 switch (conn_err) {
4632
4633 case SN_ERR_NONE:
4634 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4635 t->srv_state = SV_STCONN;
4636 return 1;
4637
4638 case SN_ERR_INTERNAL:
4639 tv_eternity(&t->cnexpire);
4640 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4641 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4642 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02004643 if (may_dequeue_tasks(t->srv, t->proxy))
4644 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004645 return 1;
4646 }
4647 /* ensure that we have enough retries left */
willy tarreau59a6cc22006-05-12 01:29:08 +02004648 if (srv_count_retry_down(t, conn_err)) {
4649 /* let's try to offer this slot to anybody */
4650 if (may_dequeue_tasks(t->srv, t->proxy))
4651 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004652 return 1;
willy tarreau59a6cc22006-05-12 01:29:08 +02004653 }
willy tarreaudfece232006-05-02 00:19:57 +02004654 } while (t->srv == NULL || t->conn_retries > 0 || !(t->proxy->options & PR_O_REDISP));
4655
4656 /* We're on our last chance, and the REDISP option was specified.
4657 * We will ignore cookie and force to balance or use the dispatcher.
4658 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004659 /* let's try to offer this slot to anybody */
4660 if (may_dequeue_tasks(t->srv, t->proxy))
4661 task_wakeup(&rq, t->srv->queue_mgt);
4662
willy tarreaudfece232006-05-02 00:19:57 +02004663 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
4664 t->srv = NULL; /* it's left to the dispatcher to choose a server */
4665 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4666 t->flags &= ~SN_CK_MASK;
4667 t->flags |= SN_CK_DOWN;
4668 }
4669 return 0;
4670}
4671
4672/* This function performs the "redispatch" part of a connection attempt. It
4673 * will assign a server if required, queue the connection if required, and
4674 * handle errors that might arise at this level. It can change the server
4675 * state. It will return 1 if it encounters an error, switches the server
4676 * state, or has to queue a connection. Otherwise, it will return 0 indicating
4677 * that the connection is ready to use.
4678 */
4679
4680int srv_redispatch_connect(struct session *t) {
4681 int conn_err;
4682
4683 /* We know that we don't have any connection pending, so we will
4684 * try to get a new one, and wait in this state if it's queued
4685 */
4686 conn_err = assign_server_and_queue(t);
4687 switch (conn_err) {
4688 case SRV_STATUS_OK:
4689 break;
4690
4691 case SRV_STATUS_NOSRV:
willy tarreau59a6cc22006-05-12 01:29:08 +02004692 /* note: it is guaranteed that t->srv == NULL here */
willy tarreaudfece232006-05-02 00:19:57 +02004693 tv_eternity(&t->cnexpire);
4694 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
4695 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaudfece232006-05-02 00:19:57 +02004696 return 1;
4697
4698 case SRV_STATUS_QUEUED:
willy tarreau45526ed2006-05-03 20:11:50 +02004699 /* FIXME-20060503 : we should use the queue timeout instead */
4700 if (t->proxy->contimeout)
4701 tv_delayfrom(&t->cnexpire, &now, t->proxy->contimeout);
4702 else
4703 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02004704 t->srv_state = SV_STIDLE;
4705 /* do nothing else and do not wake any other session up */
4706 return 1;
4707
4708 case SRV_STATUS_FULL:
4709 case SRV_STATUS_INTERNAL:
4710 default:
4711 tv_eternity(&t->cnexpire);
4712 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4713 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4714 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02004715 if (may_dequeue_tasks(t->srv, t->proxy))
4716 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004717 return 1;
4718 }
4719 /* if we get here, it's because we got SRV_STATUS_OK, which also
4720 * means that the connection has not been queued.
4721 */
4722 return 0;
4723}
4724
4725
4726/*
willy tarreau0f7af912005-12-17 12:21:26 +01004727 * manages the server FSM and its socket. It returns 1 if a state has changed
4728 * (and a resync may be needed), 0 else.
4729 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004730int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004731 int s = t->srv_state;
4732 int c = t->cli_state;
4733 struct buffer *req = t->req;
4734 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004735 appsess *asession_temp = NULL;
4736 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004737 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004738
willy tarreau750a4722005-12-17 13:21:24 +01004739#ifdef DEBUG_FULL
4740 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4741#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004742 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4743 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4744 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4745 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004746 if (s == SV_STIDLE) {
4747 if (c == CL_STHEADERS)
4748 return 0; /* stay in idle, waiting for data to reach the client side */
4749 else if (c == CL_STCLOSE ||
4750 c == CL_STSHUTW ||
4751 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4752 tv_eternity(&t->cnexpire);
willy tarreau424e04a2006-05-13 16:08:47 +02004753 if (t->pend_pos)
4754 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreau078c79a2006-05-13 12:23:58 +02004755 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 +02004756
willy tarreau0f7af912005-12-17 12:21:26 +01004757 return 1;
4758 }
willy tarreaudfece232006-05-02 00:19:57 +02004759 else {
4760 /* Right now, we will need to create a connection to the server.
4761 * We might already have tried, and got a connection pending, in
4762 * which case we will not do anything till it's pending. It's up
4763 * to any other session to release it and wake us up again.
4764 */
willy tarreau45526ed2006-05-03 20:11:50 +02004765 if (t->pend_pos) {
4766 if (tv_cmp2_ms(&t->cnexpire, &now) > 0)
4767 return 0;
4768 else {
4769 /* we've been waiting too long here */
4770 tv_eternity(&t->cnexpire);
willy tarreau078c79a2006-05-13 12:23:58 +02004771 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
4772 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
willy tarreau45526ed2006-05-03 20:11:50 +02004773 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4774 return 1;
4775 }
4776 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004777
willy tarreaudfece232006-05-02 00:19:57 +02004778 do {
4779 /* first, get a connection */
4780 if (srv_redispatch_connect(t))
4781 return t->srv_state != SV_STIDLE;
4782
4783 /* try to (re-)connect to the server, and fail if we expire the
4784 * number of retries.
4785 */
willy tarreauf32f5242006-05-02 22:54:52 +02004786 if (srv_retryable_connect(t)) {
4787 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02004788 return t->srv_state != SV_STIDLE;
willy tarreauf32f5242006-05-02 22:54:52 +02004789 }
willy tarreaudfece232006-05-02 00:19:57 +02004790
4791 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004792 }
4793 }
4794 else if (s == SV_STCONN) { /* connection in progress */
4795 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004796 //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 +01004797 return 0; /* nothing changed */
4798 }
4799 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
willy tarreaudfece232006-05-02 00:19:57 +02004800 /* timeout, asynchronous connect error or first write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004801 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
willy tarreaudfece232006-05-02 00:19:57 +02004802
willy tarreau0f7af912005-12-17 12:21:26 +01004803 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004804 if (t->srv)
4805 t->srv->cur_sess--;
willy tarreaudfece232006-05-02 00:19:57 +02004806
4807 if (t->res_sw == RES_SILENT)
willy tarreaub1285d52005-12-18 01:20:14 +01004808 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4809 else
willy tarreaudfece232006-05-02 00:19:57 +02004810 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
willy tarreaub1285d52005-12-18 01:20:14 +01004811
willy tarreaudfece232006-05-02 00:19:57 +02004812 /* ensure that we have enough retries left */
4813 if (srv_count_retry_down(t, conn_err))
4814 return 1;
4815
4816 do {
4817 /* Now we will try to either reconnect to the same server or
4818 * connect to another server. If the connection gets queued
4819 * because all servers are saturated, then we will go back to
4820 * the SV_STIDLE state.
4821 */
willy tarreauf32f5242006-05-02 22:54:52 +02004822 if (srv_retryable_connect(t)) {
4823 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02004824 return t->srv_state != SV_STCONN;
willy tarreauf32f5242006-05-02 22:54:52 +02004825 }
willy tarreaudfece232006-05-02 00:19:57 +02004826
4827 /* we need to redispatch the connection to another server */
4828 if (srv_redispatch_connect(t))
4829 return t->srv_state != SV_STCONN;
4830 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004831 }
4832 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004833 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004834
willy tarreau0f7af912005-12-17 12:21:26 +01004835 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004836 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004837 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004838 tv_eternity(&t->swexpire);
4839 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004840 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004841 if (t->proxy->srvtimeout) {
4842 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004843 /* FIXME: to prevent the server from expiring read timeouts during writes,
4844 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004845 t->srexpire = t->swexpire;
4846 }
4847 else
4848 tv_eternity(&t->swexpire);
4849 }
willy tarreau0f7af912005-12-17 12:21:26 +01004850
4851 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4852 FD_SET(t->srv_fd, StaticReadEvent);
4853 if (t->proxy->srvtimeout)
4854 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4855 else
4856 tv_eternity(&t->srexpire);
4857
4858 t->srv_state = SV_STDATA;
willy tarreau14b4d432006-04-07 18:23:29 +02004859 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004860 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004861
4862 /* if the user wants to log as soon as possible, without counting
4863 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004864 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004865 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4866 sess_log(t);
4867 }
willy tarreau0f7af912005-12-17 12:21:26 +01004868 }
willy tarreauef900ab2005-12-17 12:52:52 +01004869 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004870 t->srv_state = SV_STHEADERS;
willy tarreau14b4d432006-04-07 18:23:29 +02004871 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004872 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4873 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004874 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004875 return 1;
4876 }
4877 }
4878 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004879 /* now parse the partial (or complete) headers */
4880 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4881 char *ptr;
4882 int delete_header;
4883
4884 ptr = rep->lr;
4885
4886 /* look for the end of the current header */
4887 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4888 ptr++;
4889
4890 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004891 int line, len;
4892
4893 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004894
4895 /* first, we'll block if security checks have caught nasty things */
4896 if (t->flags & SN_CACHEABLE) {
4897 if ((t->flags & SN_CACHE_COOK) &&
4898 (t->flags & SN_SCK_ANY) &&
4899 (t->proxy->options & PR_O_CHK_CACHE)) {
4900
4901 /* we're in presence of a cacheable response containing
4902 * a set-cookie header. We'll block it as requested by
4903 * the 'checkcache' option, and send an alert.
4904 */
4905 tv_eternity(&t->srexpire);
4906 tv_eternity(&t->swexpire);
4907 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004908 if (t->srv)
4909 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01004910 t->srv_state = SV_STCLOSE;
4911 t->logs.status = 502;
4912 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4913 if (!(t->flags & SN_ERR_MASK))
4914 t->flags |= SN_ERR_PRXCOND;
4915 if (!(t->flags & SN_FINST_MASK))
4916 t->flags |= SN_FINST_H;
4917
4918 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4919 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4920
willy tarreaudfece232006-05-02 00:19:57 +02004921 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02004922 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02004923 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004924 if (may_dequeue_tasks(t->srv, t->proxy))
4925 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004926
willy tarreau97f58572005-12-18 00:53:44 +01004927 return 1;
4928 }
4929 }
4930
willy tarreau982249e2005-12-18 00:57:06 +01004931 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4932 if (t->flags & SN_SVDENY) {
4933 tv_eternity(&t->srexpire);
4934 tv_eternity(&t->swexpire);
4935 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004936 if (t->srv)
4937 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01004938 t->srv_state = SV_STCLOSE;
4939 t->logs.status = 502;
4940 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4941 if (!(t->flags & SN_ERR_MASK))
4942 t->flags |= SN_ERR_PRXCOND;
4943 if (!(t->flags & SN_FINST_MASK))
4944 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02004945 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02004946 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02004947 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004948 if (may_dequeue_tasks(t->srv, t->proxy))
4949 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004950
willy tarreau982249e2005-12-18 00:57:06 +01004951 return 1;
4952 }
4953
willy tarreau5cbea6f2005-12-17 12:48:26 +01004954 /* we'll have something else to do here : add new headers ... */
4955
willy tarreaucd878942005-12-17 13:27:43 +01004956 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4957 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004958 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004959 * insert a set-cookie here, except if we want to insert only on POST
willy tarreau4f7a1012006-05-09 23:32:26 +02004960 * requests and this one isn't. Note that servers which don't have cookies
4961 * (eg: some backup servers) will return a full cookie removal request.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004962 */
willy tarreau750a4722005-12-17 13:21:24 +01004963 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004964 t->proxy->cookie_name,
willy tarreau4f7a1012006-05-09 23:32:26 +02004965 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
willy tarreau750a4722005-12-17 13:21:24 +01004966
willy tarreau036e1ce2005-12-17 13:46:33 +01004967 t->flags |= SN_SCK_INSERTED;
4968
willy tarreau750a4722005-12-17 13:21:24 +01004969 /* Here, we will tell an eventual cache on the client side that we don't
4970 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4971 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4972 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4973 */
willy tarreau240afa62005-12-17 13:14:35 +01004974 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004975 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4976 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004977
4978 if (rep->data + rep->l < rep->h)
4979 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4980 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004981 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004982 }
4983
4984 /* headers to be added */
4985 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004986 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4987 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004988 }
4989
willy tarreau25c4ea52005-12-18 00:49:49 +01004990 /* add a "connection: close" line if needed */
4991 if (t->proxy->options & PR_O_HTTP_CLOSE)
4992 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4993
willy tarreau5cbea6f2005-12-17 12:48:26 +01004994 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004995 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004996 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004997
Willy TARREAU767ba712006-03-01 22:40:50 +01004998 /* client connection already closed or option 'httpclose' required :
4999 * we close the server's outgoing connection right now.
5000 */
5001 if ((req->l == 0) &&
5002 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
5003 FD_CLR(t->srv_fd, StaticWriteEvent);
5004 tv_eternity(&t->swexpire);
5005
5006 /* We must ensure that the read part is still alive when switching
5007 * to shutw */
5008 FD_SET(t->srv_fd, StaticReadEvent);
5009 if (t->proxy->srvtimeout)
5010 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5011
5012 shutdown(t->srv_fd, SHUT_WR);
5013 t->srv_state = SV_STSHUTW;
5014 }
5015
willy tarreau25c4ea52005-12-18 00:49:49 +01005016 /* if the user wants to log as soon as possible, without counting
5017 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005018 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005019 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
5020 t->logs.bytes = rep->h - rep->data;
5021 sess_log(t);
5022 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005023 break;
5024 }
5025
5026 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
5027 if (ptr > rep->r - 2) {
5028 /* this is a partial header, let's wait for more to come */
5029 rep->lr = ptr;
5030 break;
5031 }
5032
5033 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
5034 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
5035
5036 /* now we know that *ptr is either \r or \n,
5037 * and that there are at least 1 char after it.
5038 */
5039 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
5040 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
5041 else
5042 rep->lr = ptr + 2; /* \r\n or \n\r */
5043
5044 /*
5045 * now we know that we have a full header ; we can do whatever
5046 * we want with these pointers :
5047 * rep->h = beginning of header
5048 * ptr = end of header (first \r or \n)
5049 * rep->lr = beginning of next line (next rep->h)
5050 * rep->r = end of data (not used at this stage)
5051 */
5052
willy tarreaua1598082005-12-17 13:08:06 +01005053
willy tarreau982249e2005-12-18 00:57:06 +01005054 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01005055 t->logs.logwait &= ~LW_RESP;
5056 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01005057 switch (t->logs.status) {
5058 case 200:
5059 case 203:
5060 case 206:
5061 case 300:
5062 case 301:
5063 case 410:
5064 /* RFC2616 @13.4:
5065 * "A response received with a status code of
5066 * 200, 203, 206, 300, 301 or 410 MAY be stored
5067 * by a cache (...) unless a cache-control
5068 * directive prohibits caching."
5069 *
5070 * RFC2616 @9.5: POST method :
5071 * "Responses to this method are not cacheable,
5072 * unless the response includes appropriate
5073 * Cache-Control or Expires header fields."
5074 */
5075 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
5076 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
5077 break;
5078 default:
5079 break;
5080 }
willy tarreau4302f492005-12-18 01:00:37 +01005081 }
5082 else if (t->logs.logwait & LW_RSPHDR) {
5083 struct cap_hdr *h;
5084 int len;
5085 for (h = t->proxy->rsp_cap; h; h = h->next) {
5086 if ((h->namelen + 2 <= ptr - rep->h) &&
5087 (rep->h[h->namelen] == ':') &&
5088 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
5089
5090 if (t->rsp_cap[h->index] == NULL)
5091 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
5092
5093 len = ptr - (rep->h + h->namelen + 2);
5094 if (len > h->len)
5095 len = h->len;
5096
5097 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
5098 t->rsp_cap[h->index][len]=0;
5099 }
5100 }
5101
willy tarreaua1598082005-12-17 13:08:06 +01005102 }
5103
willy tarreau5cbea6f2005-12-17 12:48:26 +01005104 delete_header = 0;
5105
willy tarreau982249e2005-12-18 00:57:06 +01005106 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005107 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01005108 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 +01005109 max = ptr - rep->h;
5110 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01005111 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005112 trash[len++] = '\n';
5113 write(1, trash, len);
5114 }
5115
willy tarreau25c4ea52005-12-18 00:49:49 +01005116 /* remove "connection: " if needed */
5117 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
5118 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
5119 delete_header = 1;
5120 }
5121
willy tarreau5cbea6f2005-12-17 12:48:26 +01005122 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01005123 if (!delete_header && t->proxy->rsp_exp != NULL
5124 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01005125 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005126 char term;
5127
5128 term = *ptr;
5129 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01005130 exp = t->proxy->rsp_exp;
5131 do {
5132 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
5133 switch (exp->action) {
5134 case ACT_ALLOW:
5135 if (!(t->flags & SN_SVDENY))
5136 t->flags |= SN_SVALLOW;
5137 break;
5138 case ACT_REPLACE:
5139 if (!(t->flags & SN_SVDENY)) {
5140 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
5141 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
5142 }
5143 break;
5144 case ACT_REMOVE:
5145 if (!(t->flags & SN_SVDENY))
5146 delete_header = 1;
5147 break;
5148 case ACT_DENY:
5149 if (!(t->flags & SN_SVALLOW))
5150 t->flags |= SN_SVDENY;
5151 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01005152 case ACT_PASS: /* we simply don't deny this one */
5153 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005154 }
5155 break;
5156 }
willy tarreaue39cd132005-12-17 13:00:18 +01005157 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005158 *ptr = term; /* restore the string terminator */
5159 }
5160
willy tarreau97f58572005-12-18 00:53:44 +01005161 /* check for cache-control: or pragma: headers */
5162 if (!delete_header && (t->flags & SN_CACHEABLE)) {
5163 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
5164 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5165 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
5166 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01005167 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01005168 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5169 else {
5170 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01005171 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005172 t->flags &= ~SN_CACHE_COOK;
5173 }
5174 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005175 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005176 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005177 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01005178 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5179 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005180 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01005181 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01005182 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
5183 (rep->h + 25 == ptr || rep->h[25] == ',')) {
5184 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5185 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
5186 (rep->h + 21 == ptr || rep->h[21] == ',')) {
5187 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01005188 }
5189 }
5190 }
5191
willy tarreau5cbea6f2005-12-17 12:48:26 +01005192 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01005193 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01005194 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01005195 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005196 char *p1, *p2, *p3, *p4;
5197
willy tarreau97f58572005-12-18 00:53:44 +01005198 t->flags |= SN_SCK_ANY;
5199
willy tarreau5cbea6f2005-12-17 12:48:26 +01005200 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
5201
5202 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01005203 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005204 p1++;
5205
5206 if (p1 == ptr || *p1 == ';') /* end of cookie */
5207 break;
5208
5209 /* p1 is at the beginning of the cookie name */
5210 p2 = p1;
5211
5212 while (p2 < ptr && *p2 != '=' && *p2 != ';')
5213 p2++;
5214
5215 if (p2 == ptr || *p2 == ';') /* next cookie */
5216 break;
5217
5218 p3 = p2 + 1; /* skips the '=' sign */
5219 if (p3 == ptr)
5220 break;
5221
5222 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01005223 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01005224 p4++;
5225
5226 /* here, we have the cookie name between p1 and p2,
5227 * and its value between p3 and p4.
5228 * we can process it.
5229 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005230
5231 /* first, let's see if we want to capture it */
5232 if (t->proxy->capture_name != NULL &&
5233 t->logs.srv_cookie == NULL &&
5234 (p4 - p1 >= t->proxy->capture_namelen) &&
5235 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
5236 int log_len = p4 - p1;
5237
5238 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
5239 Alert("HTTP logging : out of memory.\n");
5240 }
5241
5242 if (log_len > t->proxy->capture_len)
5243 log_len = t->proxy->capture_len;
5244 memcpy(t->logs.srv_cookie, p1, log_len);
5245 t->logs.srv_cookie[log_len] = 0;
5246 }
5247
5248 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
5249 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005250 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01005251 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005252
5253 /* If the cookie is in insert mode on a known server, we'll delete
5254 * this occurrence because we'll insert another one later.
5255 * We'll delete it too if the "indirect" option is set and we're in
5256 * a direct access. */
5257 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01005258 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005259 /* this header must be deleted */
5260 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01005261 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005262 }
5263 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
5264 /* replace bytes p3->p4 with the cookie name associated
5265 * with this server since we know it.
5266 */
5267 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01005268 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005269 }
willy tarreau0174f312005-12-18 01:02:42 +01005270 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
5271 /* insert the cookie name associated with this server
5272 * before existing cookie, and insert a delimitor between them..
5273 */
5274 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
5275 p3[t->srv->cklen] = COOKIE_DELIM;
5276 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
5277 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005278 break;
5279 }
willy tarreau12350152005-12-18 01:03:27 +01005280
5281 /* first, let's see if the cookie is our appcookie*/
5282 if ((t->proxy->appsession_name != NULL) &&
5283 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
5284
5285 /* Cool... it's the right one */
5286
willy tarreaub952e1d2005-12-18 01:31:20 +01005287 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01005288 asession_temp = &local_asession;
5289
willy tarreaub952e1d2005-12-18 01:31:20 +01005290 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005291 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5292 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5293 }
5294 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
5295 asession_temp->sessid[t->proxy->appsession_len] = 0;
5296 asession_temp->serverid = NULL;
5297
5298 /* only do insert, if lookup fails */
5299 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
5300 if ((asession_temp = pool_alloc(appsess)) == NULL) {
5301 Alert("Not enought Memory process_srv():asession:calloc().\n");
5302 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
5303 return 0;
5304 }
5305 asession_temp->sessid = local_asession.sessid;
5306 asession_temp->serverid = local_asession.serverid;
5307 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01005308 }/* end if (chtbl_lookup()) */
5309 else {
willy tarreau12350152005-12-18 01:03:27 +01005310 /* free wasted memory */
5311 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01005312 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01005313
willy tarreaub952e1d2005-12-18 01:31:20 +01005314 if (asession_temp->serverid == NULL) {
5315 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005316 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5317 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5318 }
5319 asession_temp->serverid[0] = '\0';
5320 }
5321
willy tarreaub952e1d2005-12-18 01:31:20 +01005322 if (asession_temp->serverid[0] == '\0')
5323 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01005324
5325 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
5326
5327#if defined(DEBUG_HASH)
5328 print_table(&(t->proxy->htbl_proxy));
5329#endif
5330 break;
5331 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005332 else {
5333 // fprintf(stderr,"Ignoring unknown cookie : ");
5334 // write(2, p1, p2-p1);
5335 // fprintf(stderr," = ");
5336 // write(2, p3, p4-p3);
5337 // fprintf(stderr,"\n");
5338 }
5339 break; /* we don't want to loop again since there cannot be another cookie on the same line */
5340 } /* we're now at the end of the cookie value */
5341 } /* end of cookie processing */
5342
willy tarreau97f58572005-12-18 00:53:44 +01005343 /* check for any set-cookie in case we check for cacheability */
5344 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
5345 (t->proxy->options & PR_O_CHK_CACHE) &&
5346 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
5347 t->flags |= SN_SCK_ANY;
5348 }
5349
willy tarreau5cbea6f2005-12-17 12:48:26 +01005350 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01005351 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005352 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01005353
willy tarreau5cbea6f2005-12-17 12:48:26 +01005354 rep->h = rep->lr;
5355 } /* while (rep->lr < rep->r) */
5356
5357 /* end of header processing (even if incomplete) */
5358
willy tarreauef900ab2005-12-17 12:52:52 +01005359 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5360 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
5361 * full. We cannot loop here since event_srv_read will disable it only if
5362 * rep->l == rlim-data
5363 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005364 FD_SET(t->srv_fd, StaticReadEvent);
5365 if (t->proxy->srvtimeout)
5366 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5367 else
5368 tv_eternity(&t->srexpire);
5369 }
willy tarreau0f7af912005-12-17 12:21:26 +01005370
willy tarreau8337c6b2005-12-17 13:41:01 +01005371 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005372 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005373 tv_eternity(&t->srexpire);
5374 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005375 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005376 if (t->srv)
5377 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005378 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01005379 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01005380 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01005381 if (!(t->flags & SN_ERR_MASK))
5382 t->flags |= SN_ERR_SRVCL;
5383 if (!(t->flags & SN_FINST_MASK))
5384 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005385 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005386 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005387 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005388 if (may_dequeue_tasks(t->srv, t->proxy))
5389 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005390
willy tarreau0f7af912005-12-17 12:21:26 +01005391 return 1;
5392 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005393 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01005394 * since we are in header mode, if there's no space left for headers, we
5395 * won't be able to free more later, so the session will never terminate.
5396 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005397 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 +01005398 FD_CLR(t->srv_fd, StaticReadEvent);
5399 tv_eternity(&t->srexpire);
5400 shutdown(t->srv_fd, SHUT_RD);
5401 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005402 //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 +01005403 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01005404 }
5405 /* read timeout : return a 504 to the client.
5406 */
5407 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5408 tv_eternity(&t->srexpire);
5409 tv_eternity(&t->swexpire);
5410 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005411 if (t->srv)
5412 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01005413 t->srv_state = SV_STCLOSE;
5414 t->logs.status = 504;
5415 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01005416 if (!(t->flags & SN_ERR_MASK))
5417 t->flags |= SN_ERR_SRVTO;
5418 if (!(t->flags & SN_FINST_MASK))
5419 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005420 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005421 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005422 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005423 if (may_dequeue_tasks(t->srv, t->proxy))
5424 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005425
willy tarreau8337c6b2005-12-17 13:41:01 +01005426 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005427 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005428 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01005429 /* FIXME!!! here, we don't want to switch to SHUTW if the
5430 * client shuts read too early, because we may still have
5431 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01005432 * The side-effect is that if the client completely closes its
5433 * connection during SV_STHEADER, the connection to the server
5434 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01005435 */
willy tarreau036e1ce2005-12-17 13:46:33 +01005436 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005437 FD_CLR(t->srv_fd, StaticWriteEvent);
5438 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01005439
5440 /* We must ensure that the read part is still alive when switching
5441 * to shutw */
5442 FD_SET(t->srv_fd, StaticReadEvent);
5443 if (t->proxy->srvtimeout)
5444 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5445
willy tarreau0f7af912005-12-17 12:21:26 +01005446 shutdown(t->srv_fd, SHUT_WR);
5447 t->srv_state = SV_STSHUTW;
5448 return 1;
5449 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005450 /* write timeout */
5451 /* FIXME!!! here, we don't want to switch to SHUTW if the
5452 * client shuts read too early, because we may still have
5453 * some work to do on the headers.
5454 */
5455 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5456 FD_CLR(t->srv_fd, StaticWriteEvent);
5457 tv_eternity(&t->swexpire);
5458 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005459 /* We must ensure that the read part is still alive when switching
5460 * to shutw */
5461 FD_SET(t->srv_fd, StaticReadEvent);
5462 if (t->proxy->srvtimeout)
5463 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5464
5465 /* We must ensure that the read part is still alive when switching
5466 * to shutw */
5467 FD_SET(t->srv_fd, StaticReadEvent);
5468 if (t->proxy->srvtimeout)
5469 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5470
willy tarreau036e1ce2005-12-17 13:46:33 +01005471 t->srv_state = SV_STSHUTW;
5472 if (!(t->flags & SN_ERR_MASK))
5473 t->flags |= SN_ERR_SRVTO;
5474 if (!(t->flags & SN_FINST_MASK))
5475 t->flags |= SN_FINST_H;
5476 return 1;
5477 }
willy tarreau0f7af912005-12-17 12:21:26 +01005478
5479 if (req->l == 0) {
5480 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5481 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5482 tv_eternity(&t->swexpire);
5483 }
5484 }
5485 else { /* client buffer not empty */
5486 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5487 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005488 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005489 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005490 /* FIXME: to prevent the server from expiring read timeouts during writes,
5491 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005492 t->srexpire = t->swexpire;
5493 }
willy tarreau0f7af912005-12-17 12:21:26 +01005494 else
5495 tv_eternity(&t->swexpire);
5496 }
5497 }
5498
willy tarreau5cbea6f2005-12-17 12:48:26 +01005499 /* be nice with the client side which would like to send a complete header
5500 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
5501 * would read all remaining data at once ! The client should not write past rep->lr
5502 * when the server is in header state.
5503 */
5504 //return header_processed;
5505 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01005506 }
5507 else if (s == SV_STDATA) {
5508 /* read or write error */
5509 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005510 tv_eternity(&t->srexpire);
5511 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005512 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005513 if (t->srv)
5514 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005515 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005516 if (!(t->flags & SN_ERR_MASK))
5517 t->flags |= SN_ERR_SRVCL;
5518 if (!(t->flags & SN_FINST_MASK))
5519 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005520 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005521 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005522 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005523 if (may_dequeue_tasks(t->srv, t->proxy))
5524 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005525
willy tarreau0f7af912005-12-17 12:21:26 +01005526 return 1;
5527 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005528 /* last read, or end of client write */
5529 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005530 FD_CLR(t->srv_fd, StaticReadEvent);
5531 tv_eternity(&t->srexpire);
5532 shutdown(t->srv_fd, SHUT_RD);
5533 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005534 //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 +01005535 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01005536 }
5537 /* end of client read and no more data to send */
5538 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
5539 FD_CLR(t->srv_fd, StaticWriteEvent);
5540 tv_eternity(&t->swexpire);
5541 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005542 /* We must ensure that the read part is still alive when switching
5543 * to shutw */
5544 FD_SET(t->srv_fd, StaticReadEvent);
5545 if (t->proxy->srvtimeout)
5546 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5547
willy tarreaua41a8b42005-12-17 14:02:24 +01005548 t->srv_state = SV_STSHUTW;
5549 return 1;
5550 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005551 /* read timeout */
5552 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5553 FD_CLR(t->srv_fd, StaticReadEvent);
5554 tv_eternity(&t->srexpire);
5555 shutdown(t->srv_fd, SHUT_RD);
5556 t->srv_state = SV_STSHUTR;
5557 if (!(t->flags & SN_ERR_MASK))
5558 t->flags |= SN_ERR_SRVTO;
5559 if (!(t->flags & SN_FINST_MASK))
5560 t->flags |= SN_FINST_D;
5561 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005562 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005563 /* write timeout */
5564 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005565 FD_CLR(t->srv_fd, StaticWriteEvent);
5566 tv_eternity(&t->swexpire);
5567 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005568 /* We must ensure that the read part is still alive when switching
5569 * to shutw */
5570 FD_SET(t->srv_fd, StaticReadEvent);
5571 if (t->proxy->srvtimeout)
5572 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005573 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01005574 if (!(t->flags & SN_ERR_MASK))
5575 t->flags |= SN_ERR_SRVTO;
5576 if (!(t->flags & SN_FINST_MASK))
5577 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005578 return 1;
5579 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005580
5581 /* recompute request time-outs */
5582 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005583 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5584 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5585 tv_eternity(&t->swexpire);
5586 }
5587 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005588 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01005589 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5590 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005591 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005592 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005593 /* FIXME: to prevent the server from expiring read timeouts during writes,
5594 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005595 t->srexpire = t->swexpire;
5596 }
willy tarreau0f7af912005-12-17 12:21:26 +01005597 else
5598 tv_eternity(&t->swexpire);
5599 }
5600 }
5601
willy tarreaub1ff9db2005-12-17 13:51:03 +01005602 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01005603 if (rep->l == BUFSIZE) { /* no room to read more data */
5604 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5605 FD_CLR(t->srv_fd, StaticReadEvent);
5606 tv_eternity(&t->srexpire);
5607 }
5608 }
5609 else {
5610 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5611 FD_SET(t->srv_fd, StaticReadEvent);
5612 if (t->proxy->srvtimeout)
5613 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5614 else
5615 tv_eternity(&t->srexpire);
5616 }
5617 }
5618
5619 return 0; /* other cases change nothing */
5620 }
5621 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005622 if (t->res_sw == RES_ERROR) {
5623 //FD_CLR(t->srv_fd, StaticWriteEvent);
5624 tv_eternity(&t->swexpire);
5625 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005626 if (t->srv)
5627 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005628 //close(t->srv_fd);
5629 t->srv_state = SV_STCLOSE;
5630 if (!(t->flags & SN_ERR_MASK))
5631 t->flags |= SN_ERR_SRVCL;
5632 if (!(t->flags & SN_FINST_MASK))
5633 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005634 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005635 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005636 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005637 if (may_dequeue_tasks(t->srv, t->proxy))
5638 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005639
willy tarreau036e1ce2005-12-17 13:46:33 +01005640 return 1;
5641 }
5642 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005643 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005644 tv_eternity(&t->swexpire);
5645 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005646 if (t->srv)
5647 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005648 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005649 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02005650 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005651 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005652 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005653 if (may_dequeue_tasks(t->srv, t->proxy))
5654 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005655
willy tarreau0f7af912005-12-17 12:21:26 +01005656 return 1;
5657 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005658 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5659 //FD_CLR(t->srv_fd, StaticWriteEvent);
5660 tv_eternity(&t->swexpire);
5661 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005662 if (t->srv)
5663 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005664 //close(t->srv_fd);
5665 t->srv_state = SV_STCLOSE;
5666 if (!(t->flags & SN_ERR_MASK))
5667 t->flags |= SN_ERR_SRVTO;
5668 if (!(t->flags & SN_FINST_MASK))
5669 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005670 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005671 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005672 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005673 if (may_dequeue_tasks(t->srv, t->proxy))
5674 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005675
willy tarreau036e1ce2005-12-17 13:46:33 +01005676 return 1;
5677 }
willy tarreau0f7af912005-12-17 12:21:26 +01005678 else if (req->l == 0) {
5679 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5680 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5681 tv_eternity(&t->swexpire);
5682 }
5683 }
5684 else { /* buffer not empty */
5685 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5686 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005687 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005688 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005689 /* FIXME: to prevent the server from expiring read timeouts during writes,
5690 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005691 t->srexpire = t->swexpire;
5692 }
willy tarreau0f7af912005-12-17 12:21:26 +01005693 else
5694 tv_eternity(&t->swexpire);
5695 }
5696 }
5697 return 0;
5698 }
5699 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005700 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005701 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005702 tv_eternity(&t->srexpire);
5703 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005704 if (t->srv)
5705 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005706 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005707 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005708 if (!(t->flags & SN_ERR_MASK))
5709 t->flags |= SN_ERR_SRVCL;
5710 if (!(t->flags & SN_FINST_MASK))
5711 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005712 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005713 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005714 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005715 if (may_dequeue_tasks(t->srv, t->proxy))
5716 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005717
willy tarreau0f7af912005-12-17 12:21:26 +01005718 return 1;
5719 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005720 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5721 //FD_CLR(t->srv_fd, StaticReadEvent);
5722 tv_eternity(&t->srexpire);
5723 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005724 if (t->srv)
5725 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005726 //close(t->srv_fd);
5727 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02005728 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005729 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005730 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005731 if (may_dequeue_tasks(t->srv, t->proxy))
5732 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005733
willy tarreau036e1ce2005-12-17 13:46:33 +01005734 return 1;
5735 }
5736 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5737 //FD_CLR(t->srv_fd, StaticReadEvent);
5738 tv_eternity(&t->srexpire);
5739 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005740 if (t->srv)
5741 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005742 //close(t->srv_fd);
5743 t->srv_state = SV_STCLOSE;
5744 if (!(t->flags & SN_ERR_MASK))
5745 t->flags |= SN_ERR_SRVTO;
5746 if (!(t->flags & SN_FINST_MASK))
5747 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005748 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005749 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005750 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005751 if (may_dequeue_tasks(t->srv, t->proxy))
5752 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005753
willy tarreau036e1ce2005-12-17 13:46:33 +01005754 return 1;
5755 }
willy tarreau0f7af912005-12-17 12:21:26 +01005756 else if (rep->l == BUFSIZE) { /* no room to read more data */
5757 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5758 FD_CLR(t->srv_fd, StaticReadEvent);
5759 tv_eternity(&t->srexpire);
5760 }
5761 }
5762 else {
5763 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5764 FD_SET(t->srv_fd, StaticReadEvent);
5765 if (t->proxy->srvtimeout)
5766 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5767 else
5768 tv_eternity(&t->srexpire);
5769 }
5770 }
5771 return 0;
5772 }
5773 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005774 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005775 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005776 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 +01005777 write(1, trash, len);
5778 }
5779 return 0;
5780 }
5781 return 0;
5782}
5783
5784
willy tarreau5cbea6f2005-12-17 12:48:26 +01005785/* Processes the client and server jobs of a session task, then
5786 * puts it back to the wait queue in a clean state, or
5787 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005788 * the time the task accepts to wait, or TIME_ETERNITY for
5789 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005790 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005791int process_session(struct task *t) {
5792 struct session *s = t->context;
5793 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005794
willy tarreau5cbea6f2005-12-17 12:48:26 +01005795 do {
5796 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005797 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005798 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005799 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005800 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005801 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005802 } while (fsm_resync);
5803
5804 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005805 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005806 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005807
willy tarreau5cbea6f2005-12-17 12:48:26 +01005808 tv_min(&min1, &s->crexpire, &s->cwexpire);
5809 tv_min(&min2, &s->srexpire, &s->swexpire);
5810 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005811 tv_min(&t->expire, &min1, &min2);
5812
5813 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005814 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005815
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005816#ifdef DEBUG_FULL
5817 /* DEBUG code : this should never ever happen, otherwise it indicates
5818 * that a task still has something to do and will provoke a quick loop.
5819 */
5820 if (tv_remain2(&now, &t->expire) <= 0)
5821 exit(100);
5822#endif
5823
willy tarreaub952e1d2005-12-18 01:31:20 +01005824 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005825 }
5826
willy tarreau5cbea6f2005-12-17 12:48:26 +01005827 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005828 actconn--;
5829
willy tarreau982249e2005-12-18 00:57:06 +01005830 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005831 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005832 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 +01005833 write(1, trash, len);
5834 }
5835
willy tarreau750a4722005-12-17 13:21:24 +01005836 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005837 if (s->rep != NULL)
5838 s->logs.bytes = s->rep->total;
5839
willy tarreau9fe663a2005-12-17 13:02:59 +01005840 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005841 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005842 sess_log(s);
5843
willy tarreau0f7af912005-12-17 12:21:26 +01005844 /* the task MUST not be in the run queue anymore */
5845 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005846 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005847 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005848 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005849}
5850
5851
willy tarreau2812edc2006-05-04 12:09:37 +02005852/* Sets server <s> down, notifies by all available means, recounts the
5853 * remaining servers on the proxy and transfers queued sessions whenever
5854 * possible to other servers.
5855 */
5856void set_server_down(struct server *s) {
5857 struct pendconn *pc, *pc_bck, *pc_end;
5858 struct session *sess;
5859 int xferred;
5860
5861 s->state &= ~SRV_RUNNING;
5862
5863 if (s->health == s->rise) {
5864 recount_servers(s->proxy);
5865 recalc_server_map(s->proxy);
5866
5867 /* we might have sessions queued on this server and waiting for
5868 * a connection. Those which are redispatchable will be queued
5869 * to another server or to the proxy itself.
5870 */
5871 xferred = 0;
5872 FOREACH_ITEM_SAFE(pc, pc_bck, &s->pendconns, pc_end, struct pendconn *, list) {
5873 sess = pc->sess;
5874 if ((sess->proxy->options & PR_O_REDISP)) {
5875 /* The REDISP option was specified. We will ignore
5876 * cookie and force to balance or use the dispatcher.
5877 */
5878 sess->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
5879 sess->srv = NULL; /* it's left to the dispatcher to choose a server */
5880 if ((sess->flags & SN_CK_MASK) == SN_CK_VALID) {
5881 sess->flags &= ~SN_CK_MASK;
5882 sess->flags |= SN_CK_DOWN;
5883 }
5884 pendconn_free(pc);
5885 task_wakeup(&rq, sess->task);
5886 xferred++;
5887 }
5888 }
5889
5890 sprintf(trash, "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s"
5891 " %d sessions active, %d requeued, %d remaining in queue.\n",
5892 s->state & SRV_BACKUP ? "Backup " : "",
5893 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5894 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
5895 s->cur_sess, xferred, s->nbpend);
5896
willy tarreaubc2eda62006-05-04 15:16:23 +02005897 Warning("%s", trash);
5898 send_log(s->proxy, LOG_ALERT, "%s", trash);
willy tarreau2812edc2006-05-04 12:09:37 +02005899
5900 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5901 Alert("Proxy %s has no server available !\n", s->proxy->id);
5902 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5903 }
5904 }
5905 s->health = 0; /* failure */
5906}
5907
5908
willy tarreau5cbea6f2005-12-17 12:48:26 +01005909
5910/*
5911 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005912 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005913 */
5914int process_chk(struct task *t) {
5915 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005916 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005917 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005918
willy tarreauef900ab2005-12-17 12:52:52 +01005919 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005920
willy tarreau25424f82006-03-19 19:37:48 +01005921 new_chk:
5922 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005923 if (fd < 0) { /* no check currently running */
5924 //fprintf(stderr, "process_chk: 2\n");
5925 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5926 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005927 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005928 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005929
5930 /* we don't send any health-checks when the proxy is stopped or when
5931 * the server should not be checked.
5932 */
5933 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005934 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5935 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005936 task_queue(t); /* restore t to its place in the task list */
5937 return tv_remain2(&now, &t->expire);
5938 }
5939
willy tarreau5cbea6f2005-12-17 12:48:26 +01005940 /* we'll initiate a new check */
5941 s->result = 0; /* no result yet */
5942 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005943 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005944 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5945 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5946 //fprintf(stderr, "process_chk: 3\n");
5947
willy tarreaua41a8b42005-12-17 14:02:24 +01005948 /* we'll connect to the check port on the server */
5949 sa = s->addr;
5950 sa.sin_port = htons(s->check_port);
5951
willy tarreau0174f312005-12-18 01:02:42 +01005952 /* allow specific binding :
5953 * - server-specific at first
5954 * - proxy-specific next
5955 */
5956 if (s->state & SRV_BIND_SRC) {
5957 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5958 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5959 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5960 s->proxy->id, s->id);
5961 s->result = -1;
5962 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005963 }
willy tarreau0174f312005-12-18 01:02:42 +01005964 else if (s->proxy->options & PR_O_BIND_SRC) {
5965 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5966 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5967 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5968 s->proxy->id);
5969 s->result = -1;
5970 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005971 }
willy tarreau0174f312005-12-18 01:02:42 +01005972
5973 if (!s->result) {
5974 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5975 /* OK, connection in progress or established */
5976
5977 //fprintf(stderr, "process_chk: 4\n");
5978
5979 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5980 fdtab[fd].owner = t;
5981 fdtab[fd].read = &event_srv_chk_r;
5982 fdtab[fd].write = &event_srv_chk_w;
5983 fdtab[fd].state = FD_STCONN; /* connection in progress */
5984 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005985#ifdef DEBUG_FULL
5986 assert (!FD_ISSET(fd, StaticReadEvent));
5987#endif
willy tarreau0174f312005-12-18 01:02:42 +01005988 fd_insert(fd);
5989 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5990 tv_delayfrom(&t->expire, &now, s->inter);
5991 task_queue(t); /* restore t to its place in the task list */
5992 return tv_remain(&now, &t->expire);
5993 }
5994 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5995 s->result = -1; /* a real error */
5996 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005997 }
5998 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005999 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006000 }
6001
6002 if (!s->result) { /* nothing done */
6003 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01006004 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6005 tv_delayfrom(&t->expire, &t->expire, s->inter);
6006 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006007 }
6008
6009 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01006010 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01006011 s->health--; /* still good */
willy tarreau2812edc2006-05-04 12:09:37 +02006012 else
6013 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006014
6015 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01006016 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01006017 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6018 tv_delayfrom(&t->expire, &t->expire, s->inter);
6019 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006020 }
6021 else {
6022 //fprintf(stderr, "process_chk: 8\n");
6023 /* there was a test running */
6024 if (s->result > 0) { /* good server detected */
6025 //fprintf(stderr, "process_chk: 9\n");
6026 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01006027 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02006028 s->state |= SRV_RUNNING;
6029
willy tarreau535ae7a2005-12-17 12:58:00 +01006030 if (s->health == s->rise) {
willy tarreaubc2eda62006-05-04 15:16:23 +02006031 int xferred;
6032
willy tarreau62084d42006-03-24 18:57:41 +01006033 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02006034 recalc_server_map(s->proxy);
willy tarreaubc2eda62006-05-04 15:16:23 +02006035
6036 /* check if we can handle some connections queued at the proxy. We
6037 * will take as many as we can handle.
6038 */
6039 for (xferred = 0; !s->maxconn || xferred < s->maxconn; xferred++) {
6040 struct session *sess;
6041 struct pendconn *p;
6042
6043 p = pendconn_from_px(s->proxy);
6044 if (!p)
6045 break;
6046 p->sess->srv = s;
6047 sess = p->sess;
6048 pendconn_free(p);
6049 task_wakeup(&rq, sess->task);
6050 }
6051
6052 sprintf(trash,
6053 "%sServer %s/%s is UP. %d active and %d backup servers online.%s"
6054 " %d sessions requeued, %d total in queue.\n",
6055 s->state & SRV_BACKUP ? "Backup " : "",
6056 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6057 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6058 xferred, s->nbpend);
6059
6060 Warning("%s", trash);
6061 send_log(s->proxy, LOG_NOTICE, "%s", trash);
willy tarreau535ae7a2005-12-17 12:58:00 +01006062 }
willy tarreauef900ab2005-12-17 12:52:52 +01006063
willy tarreaue47c8d72005-12-17 12:55:52 +01006064 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006065 }
willy tarreauef900ab2005-12-17 12:52:52 +01006066 s->curfd = -1; /* no check running anymore */
6067 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006068 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006069 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6070 tv_delayfrom(&t->expire, &t->expire, s->inter);
6071 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006072 }
6073 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
6074 //fprintf(stderr, "process_chk: 10\n");
6075 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01006076 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01006077 s->health--; /* still good */
willy tarreau2812edc2006-05-04 12:09:37 +02006078 else
6079 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006080 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01006081 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006082 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006083 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6084 tv_delayfrom(&t->expire, &t->expire, s->inter);
6085 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006086 }
6087 /* if result is 0 and there's no timeout, we have to wait again */
6088 }
6089 //fprintf(stderr, "process_chk: 11\n");
6090 s->result = 0;
6091 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006092 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01006093}
6094
6095
willy tarreau5cbea6f2005-12-17 12:48:26 +01006096
willy tarreau59a6cc22006-05-12 01:29:08 +02006097/*
6098 * Manages a server's connection queue. If woken up, will try to dequeue as
6099 * many pending sessions as possible, and wake them up. The task has nothing
6100 * else to do, so it always returns TIME_ETERNITY.
6101 */
6102int process_srv_queue(struct task *t) {
6103 struct server *s = (struct server*)t->context;
6104 struct proxy *p = s->proxy;
6105 int xferred;
6106
6107 /* First, check if we can handle some connections queued at the proxy. We
6108 * will take as many as we can handle.
6109 */
6110 for (xferred = 0; s->cur_sess + xferred < s->maxconn; xferred++) {
6111 struct session *sess;
6112
6113 sess = pendconn_get_next_sess(s, p);
6114 if (sess == NULL)
6115 break;
6116 task_wakeup(&rq, sess->task);
6117 }
6118
6119 return TIME_ETERNITY;
6120}
6121
willy tarreau0f7af912005-12-17 12:21:26 +01006122#if STATTIME > 0
6123int stats(void);
6124#endif
6125
6126/*
willy tarreau1c2ad212005-12-18 01:11:29 +01006127 * This does 4 things :
6128 * - wake up all expired tasks
6129 * - call all runnable tasks
6130 * - call maintain_proxies() to enable/disable the listeners
6131 * - return the delay till next event in ms, -1 = wait indefinitely
6132 * Note: this part should be rewritten with the O(ln(n)) scheduler.
6133 *
willy tarreau0f7af912005-12-17 12:21:26 +01006134 */
6135
willy tarreau1c2ad212005-12-18 01:11:29 +01006136int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01006137 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01006138 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006139 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01006140
willy tarreaub952e1d2005-12-18 01:31:20 +01006141 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01006142
willy tarreau1c2ad212005-12-18 01:11:29 +01006143 /* look for expired tasks and add them to the run queue.
6144 */
willy tarreau5e698ef2006-05-02 14:51:00 +02006145 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6146 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau1c2ad212005-12-18 01:11:29 +01006147 tnext = t->next;
6148 if (t->state & TASK_RUNNING)
6149 continue;
6150
willy tarreaub952e1d2005-12-18 01:31:20 +01006151 if (tv_iseternity(&t->expire))
6152 continue;
6153
willy tarreau1c2ad212005-12-18 01:11:29 +01006154 /* wakeup expired entries. It doesn't matter if they are
6155 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01006156 */
willy tarreaub952e1d2005-12-18 01:31:20 +01006157 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006158 task_wakeup(&rq, t);
6159 }
6160 else {
6161 /* first non-runnable task. Use its expiration date as an upper bound */
6162 int temp_time = tv_remain(&now, &t->expire);
6163 if (temp_time)
6164 next_time = temp_time;
6165 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006166 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006167 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006168
willy tarreau1c2ad212005-12-18 01:11:29 +01006169 /* process each task in the run queue now. Each task may be deleted
willy tarreau7feab592006-04-22 15:13:16 +02006170 * since we only use the run queue's head. Note that any task can be
6171 * woken up by any other task and it will be processed immediately
6172 * after as it will be queued on the run queue's head.
willy tarreau1c2ad212005-12-18 01:11:29 +01006173 */
willy tarreau7feab592006-04-22 15:13:16 +02006174 while ((t = rq) != NULL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006175 int temp_time;
willy tarreau7feab592006-04-22 15:13:16 +02006176
willy tarreau1c2ad212005-12-18 01:11:29 +01006177 task_sleep(&rq, t);
6178 temp_time = t->process(t);
6179 next_time = MINTIME(temp_time, next_time);
6180 }
6181
6182 /* maintain all proxies in a consistent state. This should quickly become a task */
6183 time2 = maintain_proxies();
6184 return MINTIME(time2, next_time);
6185}
6186
6187
6188#if defined(ENABLE_EPOLL)
6189
6190/*
6191 * Main epoll() loop.
6192 */
6193
6194/* does 3 actions :
6195 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6196 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6197 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6198 *
6199 * returns 0 if initialization failed, !0 otherwise.
6200 */
6201
6202int epoll_loop(int action) {
6203 int next_time;
6204 int status;
6205 int fd;
6206
6207 int fds, count;
6208 int pr, pw, sr, sw;
6209 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
6210 struct epoll_event ev;
6211
6212 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01006213 static struct epoll_event *epoll_events = NULL;
6214 static int epoll_fd;
6215
6216 if (action == POLL_LOOP_ACTION_INIT) {
6217 epoll_fd = epoll_create(global.maxsock + 1);
6218 if (epoll_fd < 0)
6219 return 0;
6220 else {
6221 epoll_events = (struct epoll_event*)
6222 calloc(1, sizeof(struct epoll_event) * global.maxsock);
6223 PrevReadEvent = (fd_set *)
6224 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6225 PrevWriteEvent = (fd_set *)
6226 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006227 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006228 return 1;
6229 }
6230 else if (action == POLL_LOOP_ACTION_CLEAN) {
6231 if (PrevWriteEvent) free(PrevWriteEvent);
6232 if (PrevReadEvent) free(PrevReadEvent);
6233 if (epoll_events) free(epoll_events);
6234 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01006235 epoll_fd = 0;
6236 return 1;
6237 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006238
willy tarreau1c2ad212005-12-18 01:11:29 +01006239 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006240
willy tarreau1c2ad212005-12-18 01:11:29 +01006241 tv_now(&now);
6242
6243 while (1) {
6244 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01006245
6246 /* stop when there's no connection left and we don't allow them anymore */
6247 if (!actconn && listeners == 0)
6248 break;
6249
willy tarreau0f7af912005-12-17 12:21:26 +01006250#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01006251 {
6252 int time2;
6253 time2 = stats();
6254 next_time = MINTIME(time2, next_time);
6255 }
willy tarreau0f7af912005-12-17 12:21:26 +01006256#endif
6257
willy tarreau1c2ad212005-12-18 01:11:29 +01006258 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6259
6260 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
6261 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
6262
6263 if ((ro^rn) | (wo^wn)) {
6264 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6265#define FDSETS_ARE_INT_ALIGNED
6266#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01006267
willy tarreauad90a0c2005-12-18 01:09:15 +01006268#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6269#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01006270 pr = (ro >> count) & 1;
6271 pw = (wo >> count) & 1;
6272 sr = (rn >> count) & 1;
6273 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01006274#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006275 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
6276 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
6277 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6278 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01006279#endif
6280#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006281 pr = FD_ISSET(fd, PrevReadEvent);
6282 pw = FD_ISSET(fd, PrevWriteEvent);
6283 sr = FD_ISSET(fd, StaticReadEvent);
6284 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01006285#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01006286 if (!((sr^pr) | (sw^pw)))
6287 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01006288
willy tarreau1c2ad212005-12-18 01:11:29 +01006289 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
6290 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01006291
willy tarreaub952e1d2005-12-18 01:31:20 +01006292#ifdef EPOLL_CTL_MOD_WORKAROUND
6293 /* I encountered a rarely reproducible problem with
6294 * EPOLL_CTL_MOD where a modified FD (systematically
6295 * the one in epoll_events[0], fd#7) would sometimes
6296 * be set EPOLL_OUT while asked for a read ! This is
6297 * with the 2.4 epoll patch. The workaround is to
6298 * delete then recreate in case of modification.
6299 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
6300 * nor RHEL kernels.
6301 */
6302
6303 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
6304 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
6305
6306 if ((sr | sw))
6307 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
6308#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006309 if ((pr | pw)) {
6310 /* the file-descriptor already exists... */
6311 if ((sr | sw)) {
6312 /* ...and it will still exist */
6313 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
6314 // perror("epoll_ctl(MOD)");
6315 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006316 }
6317 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01006318 /* ...and it will be removed */
6319 if (fdtab[fd].state != FD_STCLOSE &&
6320 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
6321 // perror("epoll_ctl(DEL)");
6322 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006323 }
6324 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006325 } else {
6326 /* the file-descriptor did not exist, let's add it */
6327 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
6328 // perror("epoll_ctl(ADD)");
6329 // exit(1);
6330 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006331 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006332#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01006333 }
6334 ((int*)PrevReadEvent)[fds] = rn;
6335 ((int*)PrevWriteEvent)[fds] = wn;
6336 }
6337 }
6338
6339 /* now let's wait for events */
6340 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
6341 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006342
willy tarreau1c2ad212005-12-18 01:11:29 +01006343 for (count = 0; count < status; count++) {
6344 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01006345
6346 if (FD_ISSET(fd, StaticReadEvent)) {
6347 if (fdtab[fd].state == FD_STCLOSE)
6348 continue;
6349 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
6350 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006351 }
willy tarreau05be12b2006-03-19 19:35:00 +01006352
6353 if (FD_ISSET(fd, StaticWriteEvent)) {
6354 if (fdtab[fd].state == FD_STCLOSE)
6355 continue;
6356 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
6357 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006358 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006359 }
6360 }
6361 return 1;
6362}
6363#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006364
willy tarreauad90a0c2005-12-18 01:09:15 +01006365
willy tarreau5cbea6f2005-12-17 12:48:26 +01006366
willy tarreau1c2ad212005-12-18 01:11:29 +01006367#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01006368
willy tarreau1c2ad212005-12-18 01:11:29 +01006369/*
6370 * Main poll() loop.
6371 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006372
willy tarreau1c2ad212005-12-18 01:11:29 +01006373/* does 3 actions :
6374 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6375 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6376 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6377 *
6378 * returns 0 if initialization failed, !0 otherwise.
6379 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006380
willy tarreau1c2ad212005-12-18 01:11:29 +01006381int poll_loop(int action) {
6382 int next_time;
6383 int status;
6384 int fd, nbfd;
6385
6386 int fds, count;
6387 int sr, sw;
6388 unsigned rn, wn; /* read new, write new */
6389
6390 /* private data */
6391 static struct pollfd *poll_events = NULL;
6392
6393 if (action == POLL_LOOP_ACTION_INIT) {
6394 poll_events = (struct pollfd*)
6395 calloc(1, sizeof(struct pollfd) * global.maxsock);
6396 return 1;
6397 }
6398 else if (action == POLL_LOOP_ACTION_CLEAN) {
6399 if (poll_events)
6400 free(poll_events);
6401 return 1;
6402 }
6403
6404 /* OK, it's POLL_LOOP_ACTION_RUN */
6405
6406 tv_now(&now);
6407
6408 while (1) {
6409 next_time = process_runnable_tasks();
6410
6411 /* stop when there's no connection left and we don't allow them anymore */
6412 if (!actconn && listeners == 0)
6413 break;
6414
6415#if STATTIME > 0
6416 {
6417 int time2;
6418 time2 = stats();
6419 next_time = MINTIME(time2, next_time);
6420 }
6421#endif
6422
6423
6424 nbfd = 0;
6425 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6426
6427 rn = ((int*)StaticReadEvent)[fds];
6428 wn = ((int*)StaticWriteEvent)[fds];
6429
6430 if ((rn|wn)) {
6431 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6432#define FDSETS_ARE_INT_ALIGNED
6433#ifdef FDSETS_ARE_INT_ALIGNED
6434
6435#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6436#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6437 sr = (rn >> count) & 1;
6438 sw = (wn >> count) & 1;
6439#else
6440 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6441 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
6442#endif
6443#else
6444 sr = FD_ISSET(fd, StaticReadEvent);
6445 sw = FD_ISSET(fd, StaticWriteEvent);
6446#endif
6447 if ((sr|sw)) {
6448 poll_events[nbfd].fd = fd;
6449 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
6450 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01006451 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006452 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006453 }
6454 }
6455
6456 /* now let's wait for events */
6457 status = poll(poll_events, nbfd, next_time);
6458 tv_now(&now);
6459
6460 for (count = 0; status > 0 && count < nbfd; count++) {
6461 fd = poll_events[count].fd;
6462
6463 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
6464 continue;
6465
6466 /* ok, we found one active fd */
6467 status--;
6468
willy tarreau05be12b2006-03-19 19:35:00 +01006469 if (FD_ISSET(fd, StaticReadEvent)) {
6470 if (fdtab[fd].state == FD_STCLOSE)
6471 continue;
6472 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
6473 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006474 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006475
willy tarreau05be12b2006-03-19 19:35:00 +01006476 if (FD_ISSET(fd, StaticWriteEvent)) {
6477 if (fdtab[fd].state == FD_STCLOSE)
6478 continue;
6479 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
6480 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006481 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006482 }
6483 }
6484 return 1;
6485}
willy tarreauad90a0c2005-12-18 01:09:15 +01006486#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006487
willy tarreauad90a0c2005-12-18 01:09:15 +01006488
willy tarreauad90a0c2005-12-18 01:09:15 +01006489
willy tarreau1c2ad212005-12-18 01:11:29 +01006490/*
6491 * Main select() loop.
6492 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006493
willy tarreau1c2ad212005-12-18 01:11:29 +01006494/* does 3 actions :
6495 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6496 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6497 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6498 *
6499 * returns 0 if initialization failed, !0 otherwise.
6500 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006501
willy tarreauad90a0c2005-12-18 01:09:15 +01006502
willy tarreau1c2ad212005-12-18 01:11:29 +01006503int select_loop(int action) {
6504 int next_time;
6505 int status;
6506 int fd,i;
6507 struct timeval delta;
6508 int readnotnull, writenotnull;
6509 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01006510
willy tarreau1c2ad212005-12-18 01:11:29 +01006511 if (action == POLL_LOOP_ACTION_INIT) {
6512 ReadEvent = (fd_set *)
6513 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6514 WriteEvent = (fd_set *)
6515 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6516 return 1;
6517 }
6518 else if (action == POLL_LOOP_ACTION_CLEAN) {
6519 if (WriteEvent) free(WriteEvent);
6520 if (ReadEvent) free(ReadEvent);
6521 return 1;
6522 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006523
willy tarreau1c2ad212005-12-18 01:11:29 +01006524 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01006525
willy tarreau1c2ad212005-12-18 01:11:29 +01006526 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006527
willy tarreau1c2ad212005-12-18 01:11:29 +01006528 while (1) {
6529 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01006530
willy tarreau1c2ad212005-12-18 01:11:29 +01006531 /* stop when there's no connection left and we don't allow them anymore */
6532 if (!actconn && listeners == 0)
6533 break;
6534
6535#if STATTIME > 0
6536 {
6537 int time2;
6538 time2 = stats();
6539 next_time = MINTIME(time2, next_time);
6540 }
6541#endif
6542
willy tarreau1c2ad212005-12-18 01:11:29 +01006543 if (next_time > 0) { /* FIXME */
6544 /* Convert to timeval */
6545 /* to avoid eventual select loops due to timer precision */
6546 next_time += SCHEDULER_RESOLUTION;
6547 delta.tv_sec = next_time / 1000;
6548 delta.tv_usec = (next_time % 1000) * 1000;
6549 }
6550 else if (next_time == 0) { /* allow select to return immediately when needed */
6551 delta.tv_sec = delta.tv_usec = 0;
6552 }
6553
6554
6555 /* let's restore fdset state */
6556
6557 readnotnull = 0; writenotnull = 0;
6558 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
6559 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
6560 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
6561 }
6562
6563 // /* just a verification code, needs to be removed for performance */
6564 // for (i=0; i<maxfd; i++) {
6565 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
6566 // abort();
6567 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
6568 // abort();
6569 //
6570 // }
6571
6572 status = select(maxfd,
6573 readnotnull ? ReadEvent : NULL,
6574 writenotnull ? WriteEvent : NULL,
6575 NULL,
6576 (next_time >= 0) ? &delta : NULL);
6577
6578 /* this is an experiment on the separation of the select work */
6579 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6580 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6581
6582 tv_now(&now);
6583
6584 if (status > 0) { /* must proceed with events */
6585
6586 int fds;
6587 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01006588
willy tarreau1c2ad212005-12-18 01:11:29 +01006589 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
6590 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
6591 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
6592
6593 /* if we specify read first, the accepts and zero reads will be
6594 * seen first. Moreover, system buffers will be flushed faster.
6595 */
willy tarreau05be12b2006-03-19 19:35:00 +01006596 if (FD_ISSET(fd, ReadEvent)) {
6597 if (fdtab[fd].state == FD_STCLOSE)
6598 continue;
6599 fdtab[fd].read(fd);
6600 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006601
willy tarreau05be12b2006-03-19 19:35:00 +01006602 if (FD_ISSET(fd, WriteEvent)) {
6603 if (fdtab[fd].state == FD_STCLOSE)
6604 continue;
6605 fdtab[fd].write(fd);
6606 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006607 }
6608 }
6609 else {
6610 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01006611 }
willy tarreau0f7af912005-12-17 12:21:26 +01006612 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006613 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006614}
6615
6616
6617#if STATTIME > 0
6618/*
6619 * Display proxy statistics regularly. It is designed to be called from the
6620 * select_loop().
6621 */
6622int stats(void) {
6623 static int lines;
6624 static struct timeval nextevt;
6625 static struct timeval lastevt;
6626 static struct timeval starttime = {0,0};
6627 unsigned long totaltime, deltatime;
6628 int ret;
6629
willy tarreau750a4722005-12-17 13:21:24 +01006630 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01006631 deltatime = (tv_diff(&lastevt, &now)?:1);
6632 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01006633
willy tarreau9fe663a2005-12-17 13:02:59 +01006634 if (global.mode & MODE_STATS) {
6635 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006636 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01006637 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
6638 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006639 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01006640 actconn, totalconn,
6641 stats_tsk_new, stats_tsk_good,
6642 stats_tsk_left, stats_tsk_right,
6643 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
6644 }
6645 }
6646
6647 tv_delayfrom(&nextevt, &now, STATTIME);
6648
6649 lastevt=now;
6650 }
6651 ret = tv_remain(&now, &nextevt);
6652 return ret;
6653}
6654#endif
6655
6656
6657/*
6658 * this function enables proxies when there are enough free sessions,
6659 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01006660 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01006661 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01006662 */
6663static int maintain_proxies(void) {
6664 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01006665 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006666 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01006667
6668 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01006669 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01006670
6671 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01006672 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01006673 while (p) {
6674 if (p->nbconn < p->maxconn) {
6675 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006676 for (l = p->listen; l != NULL; l = l->next) {
6677 FD_SET(l->fd, StaticReadEvent);
6678 }
willy tarreau0f7af912005-12-17 12:21:26 +01006679 p->state = PR_STRUN;
6680 }
6681 }
6682 else {
6683 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006684 for (l = p->listen; l != NULL; l = l->next) {
6685 FD_CLR(l->fd, StaticReadEvent);
6686 }
willy tarreau0f7af912005-12-17 12:21:26 +01006687 p->state = PR_STIDLE;
6688 }
6689 }
6690 p = p->next;
6691 }
6692 }
6693 else { /* block all proxies */
6694 while (p) {
6695 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006696 for (l = p->listen; l != NULL; l = l->next) {
6697 FD_CLR(l->fd, StaticReadEvent);
6698 }
willy tarreau0f7af912005-12-17 12:21:26 +01006699 p->state = PR_STIDLE;
6700 }
6701 p = p->next;
6702 }
6703 }
6704
willy tarreau5cbea6f2005-12-17 12:48:26 +01006705 if (stopping) {
6706 p = proxy;
6707 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01006708 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006709 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006710 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006711 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006712 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006713 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006714
willy tarreaua41a8b42005-12-17 14:02:24 +01006715 for (l = p->listen; l != NULL; l = l->next) {
6716 fd_delete(l->fd);
6717 listeners--;
6718 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006719 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006720 }
6721 else {
6722 tleft = MINTIME(t, tleft);
6723 }
6724 }
6725 p = p->next;
6726 }
6727 }
6728 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006729}
6730
6731/*
6732 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006733 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6734 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006735 */
6736static void soft_stop(void) {
6737 struct proxy *p;
6738
6739 stopping = 1;
6740 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006741 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006742 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006743 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006744 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006745 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006746 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006747 }
willy tarreau0f7af912005-12-17 12:21:26 +01006748 p = p->next;
6749 }
6750}
6751
willy tarreaudbd3bef2006-01-20 19:35:18 +01006752static void pause_proxy(struct proxy *p) {
6753 struct listener *l;
6754 for (l = p->listen; l != NULL; l = l->next) {
6755 shutdown(l->fd, SHUT_RD);
6756 FD_CLR(l->fd, StaticReadEvent);
6757 p->state = PR_STPAUSED;
6758 }
6759}
6760
6761/*
6762 * This function temporarily disables listening so that another new instance
6763 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006764 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006765 * the proxy, or a SIGTTIN can be sent to listen again.
6766 */
6767static void pause_proxies(void) {
6768 struct proxy *p;
6769
6770 p = proxy;
6771 tv_now(&now); /* else, the old time before select will be used */
6772 while (p) {
6773 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6774 Warning("Pausing proxy %s.\n", p->id);
6775 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6776 pause_proxy(p);
6777 }
6778 p = p->next;
6779 }
6780}
6781
6782
6783/*
6784 * This function reactivates listening. This can be used after a call to
6785 * sig_pause(), for example when a new instance has failed starting up.
6786 * It is designed to be called upon reception of a SIGTTIN.
6787 */
6788static void listen_proxies(void) {
6789 struct proxy *p;
6790 struct listener *l;
6791
6792 p = proxy;
6793 tv_now(&now); /* else, the old time before select will be used */
6794 while (p) {
6795 if (p->state == PR_STPAUSED) {
6796 Warning("Enabling proxy %s.\n", p->id);
6797 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6798
6799 for (l = p->listen; l != NULL; l = l->next) {
6800 if (listen(l->fd, p->maxconn) == 0) {
6801 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6802 FD_SET(l->fd, StaticReadEvent);
6803 p->state = PR_STRUN;
6804 }
6805 else
6806 p->state = PR_STIDLE;
6807 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006808 int port;
6809
6810 if (l->addr.ss_family == AF_INET6)
6811 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6812 else
6813 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6814
willy tarreaudbd3bef2006-01-20 19:35:18 +01006815 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 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006818 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006819 /* Another port might have been enabled. Let's stop everything. */
6820 pause_proxy(p);
6821 break;
6822 }
6823 }
6824 }
6825 p = p->next;
6826 }
6827}
6828
6829
willy tarreau0f7af912005-12-17 12:21:26 +01006830/*
6831 * upon SIGUSR1, let's have a soft stop.
6832 */
6833void sig_soft_stop(int sig) {
6834 soft_stop();
6835 signal(sig, SIG_IGN);
6836}
6837
willy tarreaudbd3bef2006-01-20 19:35:18 +01006838/*
6839 * upon SIGTTOU, we pause everything
6840 */
6841void sig_pause(int sig) {
6842 pause_proxies();
6843 signal(sig, sig_pause);
6844}
willy tarreau0f7af912005-12-17 12:21:26 +01006845
willy tarreau8337c6b2005-12-17 13:41:01 +01006846/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006847 * upon SIGTTIN, let's have a soft stop.
6848 */
6849void sig_listen(int sig) {
6850 listen_proxies();
6851 signal(sig, sig_listen);
6852}
6853
6854/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006855 * this function dumps every server's state when the process receives SIGHUP.
6856 */
6857void sig_dump_state(int sig) {
6858 struct proxy *p = proxy;
6859
6860 Warning("SIGHUP received, dumping servers states.\n");
6861 while (p) {
6862 struct server *s = p->srv;
6863
willy tarreau4632c212006-05-02 23:32:51 +02006864 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006865 while (s) {
willy tarreau4632c212006-05-02 23:32:51 +02006866 snprintf(trash, sizeof(trash),
6867 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %d tot.",
6868 p->id, s->id,
6869 (s->state & SRV_RUNNING) ? "UP" : "DOWN",
6870 s->cur_sess, s->nbpend, s->cum_sess);
willy tarreau14b4d432006-04-07 18:23:29 +02006871 Warning("%s\n", trash);
6872 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01006873 s = s->next;
6874 }
willy tarreaudd07e972005-12-18 00:48:48 +01006875
willy tarreau62084d42006-03-24 18:57:41 +01006876 if (p->srv_act == 0) {
willy tarreau4632c212006-05-02 23:32:51 +02006877 snprintf(trash, sizeof(trash),
6878 "SIGHUP: Proxy %s %s ! Conn: %d act, %d pend (%d unass), %d tot.",
6879 p->id,
6880 (p->srv_bck) ? "is running on backup servers" : "has no server available",
6881 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02006882 } else {
6883 snprintf(trash, sizeof(trash),
willy tarreau4632c212006-05-02 23:32:51 +02006884 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
6885 " Conn: %d act, %d pend (%d unass), %d tot.",
6886 p->id, p->srv_act, p->srv_bck,
6887 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02006888 }
6889 Warning("%s\n", trash);
6890 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01006891
willy tarreau8337c6b2005-12-17 13:41:01 +01006892 p = p->next;
6893 }
6894 signal(sig, sig_dump_state);
6895}
6896
willy tarreau0f7af912005-12-17 12:21:26 +01006897void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006898 struct task *t, *tnext;
6899 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006900
willy tarreau5e698ef2006-05-02 14:51:00 +02006901 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6902 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006903 tnext = t->next;
6904 s = t->context;
6905 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6906 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6907 "req=%d, rep=%d, clifd=%d\n",
6908 s, tv_remain(&now, &t->expire),
6909 s->cli_state,
6910 s->srv_state,
6911 FD_ISSET(s->cli_fd, StaticReadEvent),
6912 FD_ISSET(s->cli_fd, StaticWriteEvent),
6913 FD_ISSET(s->srv_fd, StaticReadEvent),
6914 FD_ISSET(s->srv_fd, StaticWriteEvent),
6915 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6916 );
willy tarreau0f7af912005-12-17 12:21:26 +01006917 }
willy tarreau12350152005-12-18 01:03:27 +01006918}
6919
willy tarreau64a3cc32005-12-18 01:13:11 +01006920#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006921static void fast_stop(void)
6922{
6923 struct proxy *p;
6924 p = proxy;
6925 while (p) {
6926 p->grace = 0;
6927 p = p->next;
6928 }
6929 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006930}
6931
willy tarreau12350152005-12-18 01:03:27 +01006932void sig_int(int sig) {
6933 /* This would normally be a hard stop,
6934 but we want to be sure about deallocation,
6935 and so on, so we do a soft stop with
6936 0 GRACE time
6937 */
6938 fast_stop();
6939 /* If we are killed twice, we decide to die*/
6940 signal(sig, SIG_DFL);
6941}
6942
6943void sig_term(int sig) {
6944 /* This would normally be a hard stop,
6945 but we want to be sure about deallocation,
6946 and so on, so we do a soft stop with
6947 0 GRACE time
6948 */
6949 fast_stop();
6950 /* If we are killed twice, we decide to die*/
6951 signal(sig, SIG_DFL);
6952}
willy tarreau64a3cc32005-12-18 01:13:11 +01006953#endif
willy tarreau12350152005-12-18 01:03:27 +01006954
willy tarreauc1f47532005-12-18 01:08:26 +01006955/* returns the pointer to an error in the replacement string, or NULL if OK */
6956char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006957 struct hdr_exp *exp;
6958
willy tarreauc1f47532005-12-18 01:08:26 +01006959 if (replace != NULL) {
6960 char *err;
6961 err = check_replace_string(replace);
6962 if (err)
6963 return err;
6964 }
6965
willy tarreaue39cd132005-12-17 13:00:18 +01006966 while (*head != NULL)
6967 head = &(*head)->next;
6968
6969 exp = calloc(1, sizeof(struct hdr_exp));
6970
6971 exp->preg = preg;
6972 exp->replace = replace;
6973 exp->action = action;
6974 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006975
6976 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006977}
6978
willy tarreau9fe663a2005-12-17 13:02:59 +01006979
willy tarreau0f7af912005-12-17 12:21:26 +01006980/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006981 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006982 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006983int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006984
willy tarreau9fe663a2005-12-17 13:02:59 +01006985 if (!strcmp(args[0], "global")) { /* new section */
6986 /* no option, nothing special to do */
6987 return 0;
6988 }
6989 else if (!strcmp(args[0], "daemon")) {
6990 global.mode |= MODE_DAEMON;
6991 }
6992 else if (!strcmp(args[0], "debug")) {
6993 global.mode |= MODE_DEBUG;
6994 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006995 else if (!strcmp(args[0], "noepoll")) {
6996 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6997 }
6998 else if (!strcmp(args[0], "nopoll")) {
6999 cfg_polling_mechanism &= ~POLL_USE_POLL;
7000 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007001 else if (!strcmp(args[0], "quiet")) {
7002 global.mode |= MODE_QUIET;
7003 }
7004 else if (!strcmp(args[0], "stats")) {
7005 global.mode |= MODE_STATS;
7006 }
7007 else if (!strcmp(args[0], "uid")) {
7008 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007009 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007010 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007011 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007012 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007013 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007014 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007015 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007016 global.uid = atol(args[1]);
7017 }
7018 else if (!strcmp(args[0], "gid")) {
7019 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007020 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007021 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007022 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007023 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007024 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007025 return -1;
7026 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007027 global.gid = atol(args[1]);
7028 }
7029 else if (!strcmp(args[0], "nbproc")) {
7030 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007031 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007032 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007033 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007034 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007035 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007036 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007037 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007038 global.nbproc = atol(args[1]);
7039 }
7040 else if (!strcmp(args[0], "maxconn")) {
7041 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007042 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007043 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007044 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007045 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007046 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007047 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007048 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007049 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01007050#ifdef SYSTEM_MAXCONN
7051 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
7052 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);
7053 global.maxconn = DEFAULT_MAXCONN;
7054 }
7055#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01007056 }
willy tarreaub1285d52005-12-18 01:20:14 +01007057 else if (!strcmp(args[0], "ulimit-n")) {
7058 if (global.rlimit_nofile != 0) {
7059 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7060 return 0;
7061 }
7062 if (*(args[1]) == 0) {
7063 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
7064 return -1;
7065 }
7066 global.rlimit_nofile = atol(args[1]);
7067 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007068 else if (!strcmp(args[0], "chroot")) {
7069 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007070 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007071 return 0;
7072 }
7073 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007074 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007075 return -1;
7076 }
7077 global.chroot = strdup(args[1]);
7078 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007079 else if (!strcmp(args[0], "pidfile")) {
7080 if (global.pidfile != NULL) {
7081 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7082 return 0;
7083 }
7084 if (*(args[1]) == 0) {
7085 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
7086 return -1;
7087 }
7088 global.pidfile = strdup(args[1]);
7089 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007090 else if (!strcmp(args[0], "log")) { /* syslog server address */
7091 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01007092 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007093
7094 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007095 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007096 return -1;
7097 }
7098
7099 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7100 if (!strcmp(log_facilities[facility], args[2]))
7101 break;
7102
7103 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007104 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007105 exit(1);
7106 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007107
7108 level = 7; /* max syslog level = debug */
7109 if (*(args[3])) {
7110 while (level >= 0 && strcmp(log_levels[level], args[3]))
7111 level--;
7112 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007113 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007114 exit(1);
7115 }
7116 }
7117
willy tarreau9fe663a2005-12-17 13:02:59 +01007118 sa = str2sa(args[1]);
7119 if (!sa->sin_port)
7120 sa->sin_port = htons(SYSLOG_PORT);
7121
7122 if (global.logfac1 == -1) {
7123 global.logsrv1 = *sa;
7124 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007125 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007126 }
7127 else if (global.logfac2 == -1) {
7128 global.logsrv2 = *sa;
7129 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007130 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007131 }
7132 else {
7133 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
7134 return -1;
7135 }
7136
7137 }
7138 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007139 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01007140 return -1;
7141 }
7142 return 0;
7143}
7144
7145
willy tarreaua41a8b42005-12-17 14:02:24 +01007146void init_default_instance() {
7147 memset(&defproxy, 0, sizeof(defproxy));
7148 defproxy.mode = PR_MODE_TCP;
7149 defproxy.state = PR_STNEW;
7150 defproxy.maxconn = cfg_maxpconn;
7151 defproxy.conn_retries = CONN_RETRIES;
7152 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
7153}
7154
willy tarreau9fe663a2005-12-17 13:02:59 +01007155/*
7156 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
7157 */
7158int cfg_parse_listen(char *file, int linenum, char **args) {
7159 static struct proxy *curproxy = NULL;
7160 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01007161 char *err;
willy tarreau12350152005-12-18 01:03:27 +01007162 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01007163
7164 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01007165 if (!*args[1]) {
7166 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
7167 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007168 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007169 return -1;
7170 }
7171
7172 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007173 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007174 return -1;
7175 }
willy tarreaudfece232006-05-02 00:19:57 +02007176
willy tarreau9fe663a2005-12-17 13:02:59 +01007177 curproxy->next = proxy;
7178 proxy = curproxy;
willy tarreaudfece232006-05-02 00:19:57 +02007179 LIST_INIT(&curproxy->pendconns);
7180
willy tarreau9fe663a2005-12-17 13:02:59 +01007181 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01007182
7183 /* parse the listener address if any */
7184 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007185 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007186 if (!curproxy->listen)
7187 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007188 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01007189 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007190
willy tarreau9fe663a2005-12-17 13:02:59 +01007191 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01007192 curproxy->state = defproxy.state;
7193 curproxy->maxconn = defproxy.maxconn;
7194 curproxy->conn_retries = defproxy.conn_retries;
7195 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007196
7197 if (defproxy.check_req)
7198 curproxy->check_req = strdup(defproxy.check_req);
7199 curproxy->check_len = defproxy.check_len;
7200
7201 if (defproxy.cookie_name)
7202 curproxy->cookie_name = strdup(defproxy.cookie_name);
7203 curproxy->cookie_len = defproxy.cookie_len;
7204
7205 if (defproxy.capture_name)
7206 curproxy->capture_name = strdup(defproxy.capture_name);
7207 curproxy->capture_namelen = defproxy.capture_namelen;
7208 curproxy->capture_len = defproxy.capture_len;
7209
7210 if (defproxy.errmsg.msg400)
7211 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
7212 curproxy->errmsg.len400 = defproxy.errmsg.len400;
7213
7214 if (defproxy.errmsg.msg403)
7215 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
7216 curproxy->errmsg.len403 = defproxy.errmsg.len403;
7217
7218 if (defproxy.errmsg.msg408)
7219 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
7220 curproxy->errmsg.len408 = defproxy.errmsg.len408;
7221
7222 if (defproxy.errmsg.msg500)
7223 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
7224 curproxy->errmsg.len500 = defproxy.errmsg.len500;
7225
7226 if (defproxy.errmsg.msg502)
7227 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
7228 curproxy->errmsg.len502 = defproxy.errmsg.len502;
7229
7230 if (defproxy.errmsg.msg503)
7231 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
7232 curproxy->errmsg.len503 = defproxy.errmsg.len503;
7233
7234 if (defproxy.errmsg.msg504)
7235 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
7236 curproxy->errmsg.len504 = defproxy.errmsg.len504;
7237
willy tarreaua41a8b42005-12-17 14:02:24 +01007238 curproxy->clitimeout = defproxy.clitimeout;
7239 curproxy->contimeout = defproxy.contimeout;
7240 curproxy->srvtimeout = defproxy.srvtimeout;
7241 curproxy->mode = defproxy.mode;
7242 curproxy->logfac1 = defproxy.logfac1;
7243 curproxy->logsrv1 = defproxy.logsrv1;
7244 curproxy->loglev1 = defproxy.loglev1;
7245 curproxy->logfac2 = defproxy.logfac2;
7246 curproxy->logsrv2 = defproxy.logsrv2;
7247 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01007248 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01007249 curproxy->grace = defproxy.grace;
7250 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01007251 curproxy->mon_net = defproxy.mon_net;
7252 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01007253 return 0;
7254 }
7255 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007256 /* some variables may have already been initialized earlier */
7257 if (defproxy.check_req) free(defproxy.check_req);
7258 if (defproxy.cookie_name) free(defproxy.cookie_name);
7259 if (defproxy.capture_name) free(defproxy.capture_name);
7260 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
7261 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
7262 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
7263 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
7264 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
7265 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
7266 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
7267
7268 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01007269 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01007270 return 0;
7271 }
7272 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007273 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007274 return -1;
7275 }
7276
willy tarreaua41a8b42005-12-17 14:02:24 +01007277 if (!strcmp(args[0], "bind")) { /* new listen addresses */
7278 if (curproxy == &defproxy) {
7279 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7280 return -1;
7281 }
7282
7283 if (strchr(args[1], ':') == NULL) {
7284 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
7285 file, linenum, args[0]);
7286 return -1;
7287 }
7288 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007289 if (!curproxy->listen)
7290 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007291 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007292 return 0;
7293 }
willy tarreaub1285d52005-12-18 01:20:14 +01007294 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
7295 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
7296 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
7297 file, linenum, args[0]);
7298 return -1;
7299 }
7300 /* flush useless bits */
7301 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
7302 return 0;
7303 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007304 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01007305 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
7306 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
7307 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
7308 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007309 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007310 return -1;
7311 }
7312 }
7313 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01007314 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007315 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007316 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
7317 curproxy->state = PR_STNEW;
7318 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007319 else if (!strcmp(args[0], "cookie")) { /* cookie name */
7320 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007321// if (curproxy == &defproxy) {
7322// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7323// return -1;
7324// }
willy tarreaua41a8b42005-12-17 14:02:24 +01007325
willy tarreau9fe663a2005-12-17 13:02:59 +01007326 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007327// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7328// file, linenum);
7329// return 0;
7330 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007331 }
7332
7333 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007334 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
7335 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007336 return -1;
7337 }
7338 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007339 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007340
7341 cur_arg = 2;
7342 while (*(args[cur_arg])) {
7343 if (!strcmp(args[cur_arg], "rewrite")) {
7344 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01007345 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007346 else if (!strcmp(args[cur_arg], "indirect")) {
7347 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01007348 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007349 else if (!strcmp(args[cur_arg], "insert")) {
7350 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01007351 }
willy tarreau240afa62005-12-17 13:14:35 +01007352 else if (!strcmp(args[cur_arg], "nocache")) {
7353 curproxy->options |= PR_O_COOK_NOC;
7354 }
willy tarreaucd878942005-12-17 13:27:43 +01007355 else if (!strcmp(args[cur_arg], "postonly")) {
7356 curproxy->options |= PR_O_COOK_POST;
7357 }
willy tarreau0174f312005-12-18 01:02:42 +01007358 else if (!strcmp(args[cur_arg], "prefix")) {
7359 curproxy->options |= PR_O_COOK_PFX;
7360 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007361 else {
willy tarreau0174f312005-12-18 01:02:42 +01007362 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007363 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007364 return -1;
7365 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007366 cur_arg++;
7367 }
willy tarreau0174f312005-12-18 01:02:42 +01007368 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
7369 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
7370 file, linenum);
7371 return -1;
7372 }
7373
7374 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
7375 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007376 file, linenum);
7377 return -1;
7378 }
willy tarreau12350152005-12-18 01:03:27 +01007379 }/* end else if (!strcmp(args[0], "cookie")) */
7380 else if (!strcmp(args[0], "appsession")) { /* cookie name */
7381// if (curproxy == &defproxy) {
7382// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7383// return -1;
7384// }
7385
7386 if (curproxy->appsession_name != NULL) {
7387// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7388// file, linenum);
7389// return 0;
7390 free(curproxy->appsession_name);
7391 }
7392
7393 if (*(args[5]) == 0) {
7394 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
7395 file, linenum, args[0]);
7396 return -1;
7397 }
7398 have_appsession = 1;
7399 curproxy->appsession_name = strdup(args[1]);
7400 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
7401 curproxy->appsession_len = atoi(args[3]);
7402 curproxy->appsession_timeout = atoi(args[5]);
7403 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
7404 if (rc) {
7405 Alert("Error Init Appsession Hashtable.\n");
7406 return -1;
7407 }
7408 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01007409 else if (!strcmp(args[0], "capture")) {
7410 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
7411 // if (curproxy == &defproxy) {
7412 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7413 // return -1;
7414 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007415
willy tarreau4302f492005-12-18 01:00:37 +01007416 if (curproxy->capture_name != NULL) {
7417 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7418 // file, linenum, args[0]);
7419 // return 0;
7420 free(curproxy->capture_name);
7421 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007422
willy tarreau4302f492005-12-18 01:00:37 +01007423 if (*(args[4]) == 0) {
7424 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
7425 file, linenum, args[0]);
7426 return -1;
7427 }
7428 curproxy->capture_name = strdup(args[2]);
7429 curproxy->capture_namelen = strlen(curproxy->capture_name);
7430 curproxy->capture_len = atol(args[4]);
7431 if (curproxy->capture_len >= CAPTURE_LEN) {
7432 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
7433 file, linenum, CAPTURE_LEN - 1);
7434 curproxy->capture_len = CAPTURE_LEN - 1;
7435 }
7436 curproxy->to_log |= LW_COOKIE;
7437 }
7438 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
7439 struct cap_hdr *hdr;
7440
7441 if (curproxy == &defproxy) {
7442 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7443 return -1;
7444 }
7445
7446 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7447 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7448 file, linenum, args[0], args[1]);
7449 return -1;
7450 }
7451
7452 hdr = calloc(sizeof(struct cap_hdr), 1);
7453 hdr->next = curproxy->req_cap;
7454 hdr->name = strdup(args[3]);
7455 hdr->namelen = strlen(args[3]);
7456 hdr->len = atol(args[5]);
7457 hdr->index = curproxy->nb_req_cap++;
7458 curproxy->req_cap = hdr;
7459 curproxy->to_log |= LW_REQHDR;
7460 }
7461 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
7462 struct cap_hdr *hdr;
7463
7464 if (curproxy == &defproxy) {
7465 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7466 return -1;
7467 }
7468
7469 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7470 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7471 file, linenum, args[0], args[1]);
7472 return -1;
7473 }
7474 hdr = calloc(sizeof(struct cap_hdr), 1);
7475 hdr->next = curproxy->rsp_cap;
7476 hdr->name = strdup(args[3]);
7477 hdr->namelen = strlen(args[3]);
7478 hdr->len = atol(args[5]);
7479 hdr->index = curproxy->nb_rsp_cap++;
7480 curproxy->rsp_cap = hdr;
7481 curproxy->to_log |= LW_RSPHDR;
7482 }
7483 else {
7484 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007485 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007486 return -1;
7487 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007488 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007489 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007490 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007491 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007492 return 0;
7493 }
7494 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007495 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7496 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007497 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007498 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007499 curproxy->contimeout = atol(args[1]);
7500 }
7501 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007502 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007503 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7504 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007505 return 0;
7506 }
7507 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007508 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7509 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007510 return -1;
7511 }
7512 curproxy->clitimeout = atol(args[1]);
7513 }
7514 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007515 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007516 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007517 return 0;
7518 }
7519 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007520 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7521 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007522 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007523 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007524 curproxy->srvtimeout = atol(args[1]);
7525 }
7526 else if (!strcmp(args[0], "retries")) { /* connection retries */
7527 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007528 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
7529 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007530 return -1;
7531 }
7532 curproxy->conn_retries = atol(args[1]);
7533 }
7534 else if (!strcmp(args[0], "option")) {
7535 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007536 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007537 return -1;
7538 }
7539 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007540 /* enable reconnections to dispatch */
7541 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01007542#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007543 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007544 /* enable transparent proxy connections */
7545 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01007546#endif
7547 else if (!strcmp(args[1], "keepalive"))
7548 /* enable keep-alive */
7549 curproxy->options |= PR_O_KEEPALIVE;
7550 else if (!strcmp(args[1], "forwardfor"))
7551 /* insert x-forwarded-for field */
7552 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01007553 else if (!strcmp(args[1], "logasap"))
7554 /* log as soon as possible, without waiting for the session to complete */
7555 curproxy->options |= PR_O_LOGASAP;
7556 else if (!strcmp(args[1], "httpclose"))
7557 /* force connection: close in both directions in HTTP mode */
7558 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01007559 else if (!strcmp(args[1], "forceclose"))
7560 /* force connection: close in both directions in HTTP mode and enforce end of session */
7561 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01007562 else if (!strcmp(args[1], "checkcache"))
7563 /* require examination of cacheability of the 'set-cookie' field */
7564 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01007565 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01007566 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007567 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01007568 else if (!strcmp(args[1], "tcplog"))
7569 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007570 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01007571 else if (!strcmp(args[1], "dontlognull")) {
7572 /* don't log empty requests */
7573 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007574 }
willy tarreaub952e1d2005-12-18 01:31:20 +01007575 else if (!strcmp(args[1], "tcpka")) {
7576 /* enable TCP keep-alives on client and server sessions */
7577 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
7578 }
7579 else if (!strcmp(args[1], "clitcpka")) {
7580 /* enable TCP keep-alives on client sessions */
7581 curproxy->options |= PR_O_TCP_CLI_KA;
7582 }
7583 else if (!strcmp(args[1], "srvtcpka")) {
7584 /* enable TCP keep-alives on server sessions */
7585 curproxy->options |= PR_O_TCP_SRV_KA;
7586 }
Willy TARREAU3481c462006-03-01 22:37:57 +01007587 else if (!strcmp(args[1], "allbackups")) {
7588 /* Use all backup servers simultaneously */
7589 curproxy->options |= PR_O_USE_ALL_BK;
7590 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007591 else if (!strcmp(args[1], "httpchk")) {
7592 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007593 if (curproxy->check_req != NULL) {
7594 free(curproxy->check_req);
7595 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007596 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007597 if (!*args[2]) { /* no argument */
7598 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
7599 curproxy->check_len = strlen(DEF_CHECK_REQ);
7600 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01007601 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
7602 curproxy->check_req = (char *)malloc(reqlen);
7603 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7604 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007605 } else { /* more arguments : METHOD URI [HTTP_VER] */
7606 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
7607 if (*args[4])
7608 reqlen += strlen(args[4]);
7609 else
7610 reqlen += strlen("HTTP/1.0");
7611
7612 curproxy->check_req = (char *)malloc(reqlen);
7613 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7614 "%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 +01007615 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007616 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007617 else if (!strcmp(args[1], "persist")) {
7618 /* persist on using the server specified by the cookie, even when it's down */
7619 curproxy->options |= PR_O_PERSIST;
7620 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007621 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007622 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007623 return -1;
7624 }
7625 return 0;
7626 }
7627 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
7628 /* enable reconnections to dispatch */
7629 curproxy->options |= PR_O_REDISP;
7630 }
willy tarreaua1598082005-12-17 13:08:06 +01007631#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007632 else if (!strcmp(args[0], "transparent")) {
7633 /* enable transparent proxy connections */
7634 curproxy->options |= PR_O_TRANSP;
7635 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007636#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01007637 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
7638 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007639 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007640 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007641 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007642 curproxy->maxconn = atol(args[1]);
7643 }
7644 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
7645 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007646 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007647 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007648 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007649 curproxy->grace = atol(args[1]);
7650 }
7651 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01007652 if (curproxy == &defproxy) {
7653 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7654 return -1;
7655 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007656 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007657 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007658 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007659 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007660 curproxy->dispatch_addr = *str2sa(args[1]);
7661 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007662 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01007663 if (*(args[1])) {
7664 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007665 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01007666 }
willy tarreau1a3442d2006-03-24 21:03:20 +01007667 else if (!strcmp(args[1], "source")) {
7668 curproxy->options |= PR_O_BALANCE_SH;
7669 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007670 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01007671 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007672 return -1;
7673 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007674 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007675 else /* if no option is set, use round-robin by default */
7676 curproxy->options |= PR_O_BALANCE_RR;
7677 }
7678 else if (!strcmp(args[0], "server")) { /* server address */
7679 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007680 char *rport;
7681 char *raddr;
7682 short realport;
7683 int do_check;
7684
7685 if (curproxy == &defproxy) {
7686 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7687 return -1;
7688 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007689
willy tarreaua41a8b42005-12-17 14:02:24 +01007690 if (!*args[2]) {
7691 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007692 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007693 return -1;
7694 }
7695 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
7696 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7697 return -1;
7698 }
willy tarreau0174f312005-12-18 01:02:42 +01007699
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007700 /* the servers are linked backwards first */
7701 newsrv->next = curproxy->srv;
7702 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01007703 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007704
willy tarreau18a957c2006-04-12 19:26:23 +02007705 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01007706 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01007707 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01007708 newsrv->id = strdup(args[1]);
7709
7710 /* several ways to check the port component :
7711 * - IP => port=+0, relative
7712 * - IP: => port=+0, relative
7713 * - IP:N => port=N, absolute
7714 * - IP:+N => port=+N, relative
7715 * - IP:-N => port=-N, relative
7716 */
7717 raddr = strdup(args[2]);
7718 rport = strchr(raddr, ':');
7719 if (rport) {
7720 *rport++ = 0;
7721 realport = atol(rport);
7722 if (!isdigit((int)*rport))
7723 newsrv->state |= SRV_MAPPORTS;
7724 } else {
7725 realport = 0;
7726 newsrv->state |= SRV_MAPPORTS;
7727 }
7728
7729 newsrv->addr = *str2sa(raddr);
7730 newsrv->addr.sin_port = htons(realport);
7731 free(raddr);
7732
willy tarreau9fe663a2005-12-17 13:02:59 +01007733 newsrv->curfd = -1; /* no health-check in progress */
7734 newsrv->inter = DEF_CHKINTR;
7735 newsrv->rise = DEF_RISETIME;
7736 newsrv->fall = DEF_FALLTIME;
7737 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7738 cur_arg = 3;
7739 while (*args[cur_arg]) {
7740 if (!strcmp(args[cur_arg], "cookie")) {
7741 newsrv->cookie = strdup(args[cur_arg + 1]);
7742 newsrv->cklen = strlen(args[cur_arg + 1]);
7743 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007744 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007745 else if (!strcmp(args[cur_arg], "rise")) {
7746 newsrv->rise = atol(args[cur_arg + 1]);
7747 newsrv->health = newsrv->rise;
7748 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007749 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007750 else if (!strcmp(args[cur_arg], "fall")) {
7751 newsrv->fall = atol(args[cur_arg + 1]);
7752 cur_arg += 2;
7753 }
7754 else if (!strcmp(args[cur_arg], "inter")) {
7755 newsrv->inter = atol(args[cur_arg + 1]);
7756 cur_arg += 2;
7757 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007758 else if (!strcmp(args[cur_arg], "port")) {
7759 newsrv->check_port = atol(args[cur_arg + 1]);
7760 cur_arg += 2;
7761 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007762 else if (!strcmp(args[cur_arg], "backup")) {
7763 newsrv->state |= SRV_BACKUP;
7764 cur_arg ++;
7765 }
willy tarreaue3f023f2006-04-08 21:52:24 +02007766 else if (!strcmp(args[cur_arg], "weight")) {
7767 int w;
7768 w = atol(args[cur_arg + 1]);
7769 if (w < 1 || w > 256) {
7770 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
7771 file, linenum, newsrv->id, w);
7772 return -1;
7773 }
7774 newsrv->uweight = w - 1;
7775 cur_arg += 2;
7776 }
willy tarreau18a957c2006-04-12 19:26:23 +02007777 else if (!strcmp(args[cur_arg], "maxconn")) {
7778 newsrv->maxconn = atol(args[cur_arg + 1]);
7779 cur_arg += 2;
7780 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007781 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007782 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007783 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007784 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007785 }
willy tarreau0174f312005-12-18 01:02:42 +01007786 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7787 if (!*args[cur_arg + 1]) {
7788 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7789 file, linenum, "source");
7790 return -1;
7791 }
7792 newsrv->state |= SRV_BIND_SRC;
7793 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7794 cur_arg += 2;
7795 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007796 else {
willy tarreaue3f023f2006-04-08 21:52:24 +02007797 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 +01007798 file, linenum, newsrv->id);
7799 return -1;
7800 }
7801 }
7802
7803 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007804 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7805 newsrv->check_port = realport; /* by default */
7806 if (!newsrv->check_port) {
7807 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 +01007808 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007809 return -1;
7810 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007811 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007812 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007813
willy tarreau62084d42006-03-24 18:57:41 +01007814 if (newsrv->state & SRV_BACKUP)
7815 curproxy->srv_bck++;
7816 else
7817 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007818 }
7819 else if (!strcmp(args[0], "log")) { /* syslog server address */
7820 struct sockaddr_in *sa;
7821 int facility;
7822
7823 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7824 curproxy->logfac1 = global.logfac1;
7825 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007826 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007827 curproxy->logfac2 = global.logfac2;
7828 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007829 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007830 }
7831 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007832 int level;
7833
willy tarreau0f7af912005-12-17 12:21:26 +01007834 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7835 if (!strcmp(log_facilities[facility], args[2]))
7836 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007837
willy tarreau0f7af912005-12-17 12:21:26 +01007838 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007839 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007840 exit(1);
7841 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007842
willy tarreau8337c6b2005-12-17 13:41:01 +01007843 level = 7; /* max syslog level = debug */
7844 if (*(args[3])) {
7845 while (level >= 0 && strcmp(log_levels[level], args[3]))
7846 level--;
7847 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007848 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007849 exit(1);
7850 }
7851 }
7852
willy tarreau0f7af912005-12-17 12:21:26 +01007853 sa = str2sa(args[1]);
7854 if (!sa->sin_port)
7855 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007856
willy tarreau0f7af912005-12-17 12:21:26 +01007857 if (curproxy->logfac1 == -1) {
7858 curproxy->logsrv1 = *sa;
7859 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007860 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007861 }
7862 else if (curproxy->logfac2 == -1) {
7863 curproxy->logsrv2 = *sa;
7864 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007865 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007866 }
7867 else {
7868 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007869 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007870 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007871 }
7872 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007873 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007874 file, linenum);
7875 return -1;
7876 }
7877 }
willy tarreaua1598082005-12-17 13:08:06 +01007878 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007879 if (!*args[1]) {
7880 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007881 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007882 return -1;
7883 }
7884
7885 curproxy->source_addr = *str2sa(args[1]);
7886 curproxy->options |= PR_O_BIND_SRC;
7887 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007888 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7889 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007890 if (curproxy == &defproxy) {
7891 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7892 return -1;
7893 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007894
7895 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007896 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7897 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007898 return -1;
7899 }
7900
7901 preg = calloc(1, sizeof(regex_t));
7902 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007903 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007904 return -1;
7905 }
7906
willy tarreauc1f47532005-12-18 01:08:26 +01007907 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7908 if (err) {
7909 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7910 file, linenum, *err);
7911 return -1;
7912 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007913 }
7914 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7915 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007916 if (curproxy == &defproxy) {
7917 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7918 return -1;
7919 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007920
7921 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007922 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007923 return -1;
7924 }
7925
7926 preg = calloc(1, sizeof(regex_t));
7927 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007928 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007929 return -1;
7930 }
7931
7932 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7933 }
7934 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7935 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007936 if (curproxy == &defproxy) {
7937 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7938 return -1;
7939 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007940
7941 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007942 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007943 return -1;
7944 }
7945
7946 preg = calloc(1, sizeof(regex_t));
7947 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007948 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007949 return -1;
7950 }
7951
7952 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7953 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007954 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7955 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007956 if (curproxy == &defproxy) {
7957 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7958 return -1;
7959 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007960
7961 if (*(args[1]) == 0) {
7962 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7963 return -1;
7964 }
7965
7966 preg = calloc(1, sizeof(regex_t));
7967 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7968 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7969 return -1;
7970 }
7971
7972 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7973 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007974 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7975 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007976 if (curproxy == &defproxy) {
7977 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7978 return -1;
7979 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007980
7981 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007982 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007983 return -1;
7984 }
7985
7986 preg = calloc(1, sizeof(regex_t));
7987 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007988 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007989 return -1;
7990 }
7991
7992 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7993 }
7994 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7995 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007996 if (curproxy == &defproxy) {
7997 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7998 return -1;
7999 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008000
8001 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008002 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8003 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008004 return -1;
8005 }
8006
8007 preg = calloc(1, sizeof(regex_t));
8008 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008009 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008010 return -1;
8011 }
8012
willy tarreauc1f47532005-12-18 01:08:26 +01008013 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8014 if (err) {
8015 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8016 file, linenum, *err);
8017 return -1;
8018 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008019 }
8020 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
8021 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008022 if (curproxy == &defproxy) {
8023 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8024 return -1;
8025 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008026
8027 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008028 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008029 return -1;
8030 }
8031
8032 preg = calloc(1, sizeof(regex_t));
8033 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008034 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008035 return -1;
8036 }
8037
8038 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8039 }
8040 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
8041 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008042 if (curproxy == &defproxy) {
8043 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8044 return -1;
8045 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008046
8047 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008048 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008049 return -1;
8050 }
8051
8052 preg = calloc(1, sizeof(regex_t));
8053 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008054 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008055 return -1;
8056 }
8057
8058 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8059 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008060 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
8061 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008062 if (curproxy == &defproxy) {
8063 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8064 return -1;
8065 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008066
8067 if (*(args[1]) == 0) {
8068 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8069 return -1;
8070 }
8071
8072 preg = calloc(1, sizeof(regex_t));
8073 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8074 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8075 return -1;
8076 }
8077
8078 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8079 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008080 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
8081 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008082 if (curproxy == &defproxy) {
8083 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8084 return -1;
8085 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008086
8087 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008088 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008089 return -1;
8090 }
8091
8092 preg = calloc(1, sizeof(regex_t));
8093 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008094 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008095 return -1;
8096 }
8097
8098 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8099 }
8100 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008101 if (curproxy == &defproxy) {
8102 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8103 return -1;
8104 }
8105
willy tarreau9fe663a2005-12-17 13:02:59 +01008106 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008107 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008108 return 0;
8109 }
8110
8111 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008112 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008113 return -1;
8114 }
8115
willy tarreau4302f492005-12-18 01:00:37 +01008116 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
8117 }
8118 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
8119 regex_t *preg;
8120
8121 if (*(args[1]) == 0 || *(args[2]) == 0) {
8122 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8123 file, linenum, args[0]);
8124 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008125 }
willy tarreau4302f492005-12-18 01:00:37 +01008126
8127 preg = calloc(1, sizeof(regex_t));
8128 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8129 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8130 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008131 }
willy tarreau4302f492005-12-18 01:00:37 +01008132
willy tarreauc1f47532005-12-18 01:08:26 +01008133 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8134 if (err) {
8135 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8136 file, linenum, *err);
8137 return -1;
8138 }
willy tarreau4302f492005-12-18 01:00:37 +01008139 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008140 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
8141 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008142 if (curproxy == &defproxy) {
8143 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8144 return -1;
8145 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008146
8147 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008148 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008149 return -1;
8150 }
willy tarreaue39cd132005-12-17 13:00:18 +01008151
willy tarreau9fe663a2005-12-17 13:02:59 +01008152 preg = calloc(1, sizeof(regex_t));
8153 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008154 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008155 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008156 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008157
willy tarreauc1f47532005-12-18 01:08:26 +01008158 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8159 if (err) {
8160 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8161 file, linenum, *err);
8162 return -1;
8163 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008164 }
willy tarreau982249e2005-12-18 00:57:06 +01008165 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
8166 regex_t *preg;
8167 if (curproxy == &defproxy) {
8168 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8169 return -1;
8170 }
8171
8172 if (*(args[1]) == 0) {
8173 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8174 return -1;
8175 }
8176
8177 preg = calloc(1, sizeof(regex_t));
8178 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8179 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8180 return -1;
8181 }
8182
willy tarreauc1f47532005-12-18 01:08:26 +01008183 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8184 if (err) {
8185 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8186 file, linenum, *err);
8187 return -1;
8188 }
willy tarreau982249e2005-12-18 00:57:06 +01008189 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008190 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01008191 regex_t *preg;
8192 if (curproxy == &defproxy) {
8193 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8194 return -1;
8195 }
willy tarreaue39cd132005-12-17 13:00:18 +01008196
willy tarreaua41a8b42005-12-17 14:02:24 +01008197 if (*(args[1]) == 0 || *(args[2]) == 0) {
8198 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8199 file, linenum, args[0]);
8200 return -1;
8201 }
willy tarreaue39cd132005-12-17 13:00:18 +01008202
willy tarreaua41a8b42005-12-17 14:02:24 +01008203 preg = calloc(1, sizeof(regex_t));
8204 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8205 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8206 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008207 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008208
willy tarreauc1f47532005-12-18 01:08:26 +01008209 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8210 if (err) {
8211 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8212 file, linenum, *err);
8213 return -1;
8214 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008215 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008216 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
8217 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008218 if (curproxy == &defproxy) {
8219 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8220 return -1;
8221 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008222
8223 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008224 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008225 return -1;
8226 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008227
willy tarreau9fe663a2005-12-17 13:02:59 +01008228 preg = calloc(1, sizeof(regex_t));
8229 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008230 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008231 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008232 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008233
willy tarreauc1f47532005-12-18 01:08:26 +01008234 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8235 if (err) {
8236 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8237 file, linenum, *err);
8238 return -1;
8239 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008240 }
willy tarreau982249e2005-12-18 00:57:06 +01008241 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
8242 regex_t *preg;
8243 if (curproxy == &defproxy) {
8244 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8245 return -1;
8246 }
8247
8248 if (*(args[1]) == 0) {
8249 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8250 return -1;
8251 }
8252
8253 preg = calloc(1, sizeof(regex_t));
8254 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8255 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8256 return -1;
8257 }
8258
willy tarreauc1f47532005-12-18 01:08:26 +01008259 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8260 if (err) {
8261 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8262 file, linenum, *err);
8263 return -1;
8264 }
willy tarreau982249e2005-12-18 00:57:06 +01008265 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008266 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008267 if (curproxy == &defproxy) {
8268 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8269 return -1;
8270 }
8271
willy tarreau9fe663a2005-12-17 13:02:59 +01008272 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008273 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008274 return 0;
8275 }
8276
8277 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008278 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008279 return -1;
8280 }
8281
8282 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
8283 }
willy tarreauc1f47532005-12-18 01:08:26 +01008284 else if (!strcmp(args[0], "errorloc") ||
8285 !strcmp(args[0], "errorloc302") ||
8286 !strcmp(args[0], "errorloc303")) { /* error location */
8287 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008288 char *err;
8289
willy tarreaueedaa9f2005-12-17 14:08:03 +01008290 // if (curproxy == &defproxy) {
8291 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8292 // return -1;
8293 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01008294
willy tarreau8337c6b2005-12-17 13:41:01 +01008295 if (*(args[2]) == 0) {
8296 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
8297 return -1;
8298 }
8299
8300 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01008301 if (!strcmp(args[0], "errorloc303")) {
8302 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
8303 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
8304 } else {
8305 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
8306 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
8307 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008308
8309 if (errnum == 400) {
8310 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008311 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008312 free(curproxy->errmsg.msg400);
8313 }
8314 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008315 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008316 }
8317 else if (errnum == 403) {
8318 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008319 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008320 free(curproxy->errmsg.msg403);
8321 }
8322 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008323 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008324 }
8325 else if (errnum == 408) {
8326 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008327 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008328 free(curproxy->errmsg.msg408);
8329 }
8330 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008331 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008332 }
8333 else if (errnum == 500) {
8334 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008335 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008336 free(curproxy->errmsg.msg500);
8337 }
8338 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008339 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008340 }
8341 else if (errnum == 502) {
8342 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008343 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008344 free(curproxy->errmsg.msg502);
8345 }
8346 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008347 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008348 }
8349 else if (errnum == 503) {
8350 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008351 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008352 free(curproxy->errmsg.msg503);
8353 }
8354 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008355 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008356 }
8357 else if (errnum == 504) {
8358 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008359 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008360 free(curproxy->errmsg.msg504);
8361 }
8362 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008363 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008364 }
8365 else {
8366 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
8367 free(err);
8368 }
8369 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008370 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008371 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01008372 return -1;
8373 }
8374 return 0;
8375}
willy tarreaue39cd132005-12-17 13:00:18 +01008376
willy tarreau5cbea6f2005-12-17 12:48:26 +01008377
willy tarreau9fe663a2005-12-17 13:02:59 +01008378/*
8379 * This function reads and parses the configuration file given in the argument.
8380 * returns 0 if OK, -1 if error.
8381 */
8382int readcfgfile(char *file) {
8383 char thisline[256];
8384 char *line;
8385 FILE *f;
8386 int linenum = 0;
8387 char *end;
8388 char *args[MAX_LINE_ARGS];
8389 int arg;
8390 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01008391 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01008392 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01008393
willy tarreau9fe663a2005-12-17 13:02:59 +01008394 struct proxy *curproxy = NULL;
8395 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01008396
willy tarreau9fe663a2005-12-17 13:02:59 +01008397 if ((f=fopen(file,"r")) == NULL)
8398 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008399
willy tarreaueedaa9f2005-12-17 14:08:03 +01008400 init_default_instance();
8401
willy tarreau9fe663a2005-12-17 13:02:59 +01008402 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
8403 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008404
willy tarreau9fe663a2005-12-17 13:02:59 +01008405 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01008406
willy tarreau9fe663a2005-12-17 13:02:59 +01008407 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01008408 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01008409 line++;
8410
8411 arg = 0;
8412 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01008413
willy tarreau9fe663a2005-12-17 13:02:59 +01008414 while (*line && arg < MAX_LINE_ARGS) {
8415 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
8416 * C equivalent value. Other combinations left unchanged (eg: \1).
8417 */
8418 if (*line == '\\') {
8419 int skip = 0;
8420 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
8421 *line = line[1];
8422 skip = 1;
8423 }
8424 else if (line[1] == 'r') {
8425 *line = '\r';
8426 skip = 1;
8427 }
8428 else if (line[1] == 'n') {
8429 *line = '\n';
8430 skip = 1;
8431 }
8432 else if (line[1] == 't') {
8433 *line = '\t';
8434 skip = 1;
8435 }
willy tarreauc1f47532005-12-18 01:08:26 +01008436 else if (line[1] == 'x') {
8437 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
8438 unsigned char hex1, hex2;
8439 hex1 = toupper(line[2]) - '0';
8440 hex2 = toupper(line[3]) - '0';
8441 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
8442 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
8443 *line = (hex1<<4) + hex2;
8444 skip = 3;
8445 }
8446 else {
8447 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
8448 return -1;
8449 }
8450 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008451 if (skip) {
8452 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
8453 end -= skip;
8454 }
8455 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008456 }
willy tarreaua1598082005-12-17 13:08:06 +01008457 else if (*line == '#' || *line == '\n' || *line == '\r') {
8458 /* end of string, end of loop */
8459 *line = 0;
8460 break;
8461 }
willy tarreauc29948c2005-12-17 13:10:27 +01008462 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008463 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01008464 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01008465 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01008466 line++;
8467 args[++arg] = line;
8468 }
8469 else {
8470 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008471 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008472 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008473
willy tarreau9fe663a2005-12-17 13:02:59 +01008474 /* empty line */
8475 if (!**args)
8476 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01008477
willy tarreau9fe663a2005-12-17 13:02:59 +01008478 /* zero out remaining args */
8479 while (++arg < MAX_LINE_ARGS) {
8480 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008481 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008482
willy tarreaua41a8b42005-12-17 14:02:24 +01008483 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01008484 confsect = CFG_LISTEN;
8485 else if (!strcmp(args[0], "global")) /* global config */
8486 confsect = CFG_GLOBAL;
8487 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01008488
willy tarreau9fe663a2005-12-17 13:02:59 +01008489 switch (confsect) {
8490 case CFG_LISTEN:
8491 if (cfg_parse_listen(file, linenum, args) < 0)
8492 return -1;
8493 break;
8494 case CFG_GLOBAL:
8495 if (cfg_parse_global(file, linenum, args) < 0)
8496 return -1;
8497 break;
8498 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01008499 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008500 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008501 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008502
8503
willy tarreau0f7af912005-12-17 12:21:26 +01008504 }
8505 fclose(f);
8506
8507 /*
8508 * Now, check for the integrity of all that we have collected.
8509 */
8510
Willy TARREAU3759f982006-03-01 22:44:17 +01008511 /* will be needed further to delay some tasks */
8512 tv_now(&now);
8513
willy tarreau0f7af912005-12-17 12:21:26 +01008514 if ((curproxy = proxy) == NULL) {
8515 Alert("parsing %s : no <listen> line. Nothing to do !\n",
8516 file);
8517 return -1;
8518 }
8519
8520 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01008521 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01008522 curproxy = curproxy->next;
8523 continue;
8524 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008525
8526 if (curproxy->listen == NULL) {
8527 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);
8528 cfgerr++;
8529 }
8530 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01008531 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01008532 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008533 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
8534 file, curproxy->id);
8535 cfgerr++;
8536 }
8537 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
8538 if (curproxy->options & PR_O_TRANSP) {
8539 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
8540 file, curproxy->id);
8541 cfgerr++;
8542 }
8543 else if (curproxy->srv == NULL) {
8544 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
8545 file, curproxy->id);
8546 cfgerr++;
8547 }
willy tarreaua1598082005-12-17 13:08:06 +01008548 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008549 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
8550 file, curproxy->id);
8551 }
8552 }
8553 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01008554 if (curproxy->cookie_name != NULL) {
8555 Warning("parsing %s : cookie will be ignored for listener %s.\n",
8556 file, curproxy->id);
8557 }
8558 if ((newsrv = curproxy->srv) != NULL) {
8559 Warning("parsing %s : servers will be ignored for listener %s.\n",
8560 file, curproxy->id);
8561 }
willy tarreaue39cd132005-12-17 13:00:18 +01008562 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008563 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
8564 file, curproxy->id);
8565 }
willy tarreaue39cd132005-12-17 13:00:18 +01008566 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008567 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
8568 file, curproxy->id);
8569 }
8570 }
8571 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
8572 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
8573 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
8574 file, curproxy->id);
8575 cfgerr++;
8576 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008577 }
willy tarreaue3f023f2006-04-08 21:52:24 +02008578
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008579 /* first, we will invert the servers list order */
8580 newsrv = NULL;
8581 while (curproxy->srv) {
8582 struct server *next;
8583
8584 next = curproxy->srv->next;
8585 curproxy->srv->next = newsrv;
8586 newsrv = curproxy->srv;
8587 if (!next)
8588 break;
8589 curproxy->srv = next;
8590 }
8591
8592 /* now, newsrv == curproxy->srv */
8593 if (newsrv) {
8594 struct server *srv;
8595 int pgcd;
8596 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02008597
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008598 /* We will factor the weights to reduce the table,
8599 * using Euclide's largest common divisor algorithm
8600 */
8601 pgcd = newsrv->uweight + 1;
8602 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
8603 int t, w;
8604
8605 w = srv->uweight + 1;
8606 while (w) {
8607 t = pgcd % w;
8608 pgcd = w;
8609 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02008610 }
willy tarreau0f7af912005-12-17 12:21:26 +01008611 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008612
8613 act = bck = 0;
8614 for (srv = newsrv; srv; srv = srv->next) {
8615 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
8616 if (srv->state & SRV_BACKUP)
8617 bck += srv->eweight + 1;
8618 else
8619 act += srv->eweight + 1;
8620 }
8621
8622 /* this is the largest map we will ever need for this servers list */
8623 if (act < bck)
8624 act = bck;
8625
8626 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
8627 /* recounts servers and their weights */
8628 recount_servers(curproxy);
8629 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01008630 }
willy tarreau25c4ea52005-12-18 00:49:49 +01008631
8632 if (curproxy->options & PR_O_LOGASAP)
8633 curproxy->to_log &= ~LW_BYTES;
8634
willy tarreau8337c6b2005-12-17 13:41:01 +01008635 if (curproxy->errmsg.msg400 == NULL) {
8636 curproxy->errmsg.msg400 = (char *)HTTP_400;
8637 curproxy->errmsg.len400 = strlen(HTTP_400);
8638 }
8639 if (curproxy->errmsg.msg403 == NULL) {
8640 curproxy->errmsg.msg403 = (char *)HTTP_403;
8641 curproxy->errmsg.len403 = strlen(HTTP_403);
8642 }
8643 if (curproxy->errmsg.msg408 == NULL) {
8644 curproxy->errmsg.msg408 = (char *)HTTP_408;
8645 curproxy->errmsg.len408 = strlen(HTTP_408);
8646 }
8647 if (curproxy->errmsg.msg500 == NULL) {
8648 curproxy->errmsg.msg500 = (char *)HTTP_500;
8649 curproxy->errmsg.len500 = strlen(HTTP_500);
8650 }
8651 if (curproxy->errmsg.msg502 == NULL) {
8652 curproxy->errmsg.msg502 = (char *)HTTP_502;
8653 curproxy->errmsg.len502 = strlen(HTTP_502);
8654 }
8655 if (curproxy->errmsg.msg503 == NULL) {
8656 curproxy->errmsg.msg503 = (char *)HTTP_503;
8657 curproxy->errmsg.len503 = strlen(HTTP_503);
8658 }
8659 if (curproxy->errmsg.msg504 == NULL) {
8660 curproxy->errmsg.msg504 = (char *)HTTP_504;
8661 curproxy->errmsg.len504 = strlen(HTTP_504);
8662 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008663
willy tarreau59a6cc22006-05-12 01:29:08 +02008664 /*
8665 * If this server supports a maxconn parameter, it needs a dedicated
8666 * tasks to fill the emptied slots when a connection leaves.
8667 */
8668 newsrv = curproxy->srv;
8669 while (newsrv != NULL) {
8670 if (newsrv->maxconn > 0) {
8671 struct task *t;
8672
8673 if ((t = pool_alloc(task)) == NULL) {
8674 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8675 return -1;
8676 }
8677
8678 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
8679 t->wq = LIST_HEAD(wait_queue[1]); /* already assigned to the eternity queue */
8680 t->state = TASK_IDLE;
8681 t->process = process_srv_queue;
8682 t->context = newsrv;
8683 newsrv->queue_mgt = t;
8684
8685 /* never run it unless specifically woken up */
8686 tv_eternity(&t->expire);
8687 task_queue(t);
8688 }
8689 newsrv = newsrv->next;
8690 }
8691
Willy TARREAU3759f982006-03-01 22:44:17 +01008692 /* now we'll start this proxy's health checks if any */
8693 /* 1- count the checkers to run simultaneously */
8694 nbchk = 0;
8695 mininter = 0;
8696 newsrv = curproxy->srv;
8697 while (newsrv != NULL) {
8698 if (newsrv->state & SRV_CHECKED) {
8699 if (!mininter || mininter > newsrv->inter)
8700 mininter = newsrv->inter;
8701 nbchk++;
8702 }
8703 newsrv = newsrv->next;
8704 }
8705
8706 /* 2- start them as far as possible from each others while respecting
8707 * their own intervals. For this, we will start them after their own
8708 * interval added to the min interval divided by the number of servers,
8709 * weighted by the server's position in the list.
8710 */
8711 if (nbchk > 0) {
8712 struct task *t;
8713 int srvpos;
8714
8715 newsrv = curproxy->srv;
8716 srvpos = 0;
8717 while (newsrv != NULL) {
8718 /* should this server be checked ? */
8719 if (newsrv->state & SRV_CHECKED) {
8720 if ((t = pool_alloc(task)) == NULL) {
8721 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8722 return -1;
8723 }
8724
8725 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02008726 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
Willy TARREAU3759f982006-03-01 22:44:17 +01008727 t->state = TASK_IDLE;
8728 t->process = process_chk;
8729 t->context = newsrv;
8730
8731 /* check this every ms */
8732 tv_delayfrom(&t->expire, &now,
8733 newsrv->inter + mininter * srvpos / nbchk);
8734 task_queue(t);
8735 //task_wakeup(&rq, t);
8736 srvpos++;
8737 }
8738 newsrv = newsrv->next;
8739 }
8740 }
8741
willy tarreau0f7af912005-12-17 12:21:26 +01008742 curproxy = curproxy->next;
8743 }
8744 if (cfgerr > 0) {
8745 Alert("Errors found in configuration file, aborting.\n");
8746 return -1;
8747 }
8748 else
8749 return 0;
8750}
8751
8752
8753/*
8754 * This function initializes all the necessary variables. It only returns
8755 * if everything is OK. If something fails, it exits.
8756 */
8757void init(int argc, char **argv) {
8758 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01008759 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01008760 char *old_argv = *argv;
8761 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008762 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008763
8764 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01008765 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01008766 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01008767 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01008768 exit(1);
8769 }
8770
willy tarreau746e26b2006-03-25 11:14:35 +01008771#ifdef HAPROXY_MEMMAX
8772 global.rlimit_memmax = HAPROXY_MEMMAX;
8773#endif
8774
Willy TARREAUa9e75f62006-03-01 22:27:48 +01008775 /* initialize the libc's localtime structures once for all so that we
8776 * won't be missing memory if we want to send alerts under OOM conditions.
8777 */
8778 tv_now(&now);
8779 localtime(&now.tv_sec);
8780
willy tarreau4302f492005-12-18 01:00:37 +01008781 /* initialize the log header encoding map : '{|}"#' should be encoded with
8782 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
8783 * URL encoding only requires '"', '#' to be encoded as well as non-
8784 * printable characters above.
8785 */
8786 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
8787 memset(url_encode_map, 0, sizeof(url_encode_map));
8788 for (i = 0; i < 32; i++) {
8789 FD_SET(i, hdr_encode_map);
8790 FD_SET(i, url_encode_map);
8791 }
8792 for (i = 127; i < 256; i++) {
8793 FD_SET(i, hdr_encode_map);
8794 FD_SET(i, url_encode_map);
8795 }
8796
8797 tmp = "\"#{|}";
8798 while (*tmp) {
8799 FD_SET(*tmp, hdr_encode_map);
8800 tmp++;
8801 }
8802
8803 tmp = "\"#";
8804 while (*tmp) {
8805 FD_SET(*tmp, url_encode_map);
8806 tmp++;
8807 }
8808
willy tarreau64a3cc32005-12-18 01:13:11 +01008809 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8810#if defined(ENABLE_POLL)
8811 cfg_polling_mechanism |= POLL_USE_POLL;
8812#endif
8813#if defined(ENABLE_EPOLL)
8814 cfg_polling_mechanism |= POLL_USE_EPOLL;
8815#endif
8816
willy tarreau0f7af912005-12-17 12:21:26 +01008817 pid = getpid();
8818 progname = *argv;
8819 while ((tmp = strchr(progname, '/')) != NULL)
8820 progname = tmp + 1;
8821
8822 argc--; argv++;
8823 while (argc > 0) {
8824 char *flag;
8825
8826 if (**argv == '-') {
8827 flag = *argv+1;
8828
8829 /* 1 arg */
8830 if (*flag == 'v') {
8831 display_version();
8832 exit(0);
8833 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008834#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008835 else if (*flag == 'd' && flag[1] == 'e')
8836 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008837#endif
8838#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008839 else if (*flag == 'd' && flag[1] == 'p')
8840 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008841#endif
willy tarreau982249e2005-12-18 00:57:06 +01008842 else if (*flag == 'V')
8843 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008844 else if (*flag == 'd' && flag[1] == 'b')
8845 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008846 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008847 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008848 else if (*flag == 'c')
8849 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008850 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008851 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008852 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008853 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01008854 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8855 /* list of pids to finish ('f') or terminate ('t') */
8856
8857 if (flag[1] == 'f')
8858 oldpids_sig = SIGUSR1; /* finish then exit */
8859 else
8860 oldpids_sig = SIGTERM; /* terminate immediately */
8861 argv++; argc--;
8862
8863 if (argc > 0) {
8864 oldpids = calloc(argc, sizeof(int));
8865 while (argc > 0) {
8866 oldpids[nb_oldpids] = atol(*argv);
8867 if (oldpids[nb_oldpids] <= 0)
8868 usage(old_argv);
8869 argc--; argv++;
8870 nb_oldpids++;
8871 }
8872 }
8873 }
willy tarreau2c513732006-04-15 19:25:16 +02008874#if STATTIME > 0
8875 else if (*flag == 's')
8876 arg_mode |= MODE_STATS;
8877 else if (*flag == 'l')
8878 arg_mode |= MODE_LOG;
8879#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008880 else { /* >=2 args */
8881 argv++; argc--;
8882 if (argc == 0)
8883 usage(old_argv);
8884
8885 switch (*flag) {
8886 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008887 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008888 case 'N' : cfg_maxpconn = atol(*argv); break;
8889 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008890 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008891 default: usage(old_argv);
8892 }
8893 }
8894 }
8895 else
8896 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008897 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008898 }
8899
willy tarreaud0fb4652005-12-18 01:32:04 +01008900 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008901 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8902 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008903
willy tarreau0f7af912005-12-17 12:21:26 +01008904 if (!cfg_cfgfile)
8905 usage(old_argv);
8906
8907 gethostname(hostname, MAX_HOSTNAME_LEN);
8908
willy tarreau12350152005-12-18 01:03:27 +01008909 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008910 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008911 if (readcfgfile(cfg_cfgfile) < 0) {
8912 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8913 exit(1);
8914 }
willy tarreau12350152005-12-18 01:03:27 +01008915 if (have_appsession)
8916 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008917
willy tarreau982249e2005-12-18 00:57:06 +01008918 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008919 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8920 exit(0);
8921 }
8922
willy tarreau9fe663a2005-12-17 13:02:59 +01008923 if (cfg_maxconn > 0)
8924 global.maxconn = cfg_maxconn;
8925
willy tarreaufe2c5c12005-12-17 14:14:34 +01008926 if (cfg_pidfile) {
8927 if (global.pidfile)
8928 free(global.pidfile);
8929 global.pidfile = strdup(cfg_pidfile);
8930 }
8931
willy tarreau9fe663a2005-12-17 13:02:59 +01008932 if (global.maxconn == 0)
8933 global.maxconn = DEFAULT_MAXCONN;
8934
Willy TARREAU203b0b62006-03-12 18:00:28 +01008935 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008936
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008937 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008938 /* command line debug mode inhibits configuration mode */
8939 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8940 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008941 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8942 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008943
8944 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8945 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8946 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8947 }
8948
8949 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008950 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8951 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008952 global.nbproc = 1;
8953 }
8954
8955 if (global.nbproc < 1)
8956 global.nbproc = 1;
8957
willy tarreau0f7af912005-12-17 12:21:26 +01008958 StaticReadEvent = (fd_set *)calloc(1,
8959 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008960 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008961 StaticWriteEvent = (fd_set *)calloc(1,
8962 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008963 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008964
8965 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008966 sizeof(struct fdtab) * (global.maxsock));
8967 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008968 fdtab[i].state = FD_STCLOSE;
8969 }
8970}
8971
8972/*
willy tarreau41310e72006-03-25 18:17:56 +01008973 * this function starts all the proxies. Its return value is composed from
8974 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8975 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008976 */
willy tarreau41310e72006-03-25 18:17:56 +01008977int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008978 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008979 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008980 int err = ERR_NONE;
8981 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008982
8983 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008984 if (curproxy->state != PR_STNEW)
8985 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01008986
willy tarreau41310e72006-03-25 18:17:56 +01008987 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01008988 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008989 if (listener->fd != -1)
8990 continue; /* already initialized */
8991
8992 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
8993 if (verbose)
8994 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8995 curproxy->id);
8996 err |= ERR_RETRYABLE;
8997 pxerr |= 1;
8998 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008999 }
willy tarreau0f7af912005-12-17 12:21:26 +01009000
willy tarreaua41a8b42005-12-17 14:02:24 +01009001 if (fd >= global.maxsock) {
9002 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
9003 curproxy->id);
9004 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009005 err |= ERR_FATAL;
9006 pxerr |= 1;
9007 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009008 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009009
willy tarreaua41a8b42005-12-17 14:02:24 +01009010 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
9011 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
9012 (char *) &one, sizeof(one)) == -1)) {
9013 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
9014 curproxy->id);
9015 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009016 err |= ERR_FATAL;
9017 pxerr |= 1;
9018 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009019 }
willy tarreau0f7af912005-12-17 12:21:26 +01009020
willy tarreaua41a8b42005-12-17 14:02:24 +01009021 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
9022 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
9023 curproxy->id);
9024 }
willy tarreau0f7af912005-12-17 12:21:26 +01009025
willy tarreaua41a8b42005-12-17 14:02:24 +01009026 if (bind(fd,
9027 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01009028 listener->addr.ss_family == AF_INET6 ?
9029 sizeof(struct sockaddr_in6) :
9030 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009031 if (verbose)
9032 Alert("cannot bind socket for proxy %s. Aborting.\n",
9033 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009034 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009035 err |= ERR_RETRYABLE;
9036 pxerr |= 1;
9037 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009038 }
willy tarreau0f7af912005-12-17 12:21:26 +01009039
willy tarreaua41a8b42005-12-17 14:02:24 +01009040 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009041 if (verbose)
9042 Alert("cannot listen to socket for proxy %s. Aborting.\n",
9043 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009044 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009045 err |= ERR_RETRYABLE;
9046 pxerr |= 1;
9047 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009048 }
willy tarreau0f7af912005-12-17 12:21:26 +01009049
willy tarreau41310e72006-03-25 18:17:56 +01009050 /* the socket is ready */
9051 listener->fd = fd;
9052
willy tarreaua41a8b42005-12-17 14:02:24 +01009053 /* the function for the accept() event */
9054 fdtab[fd].read = &event_accept;
9055 fdtab[fd].write = NULL; /* never called */
9056 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01009057 fdtab[fd].state = FD_STLISTEN;
9058 FD_SET(fd, StaticReadEvent);
9059 fd_insert(fd);
9060 listeners++;
9061 }
willy tarreau41310e72006-03-25 18:17:56 +01009062
9063 if (!pxerr) {
9064 curproxy->state = PR_STRUN;
9065 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
9066 }
willy tarreau0f7af912005-12-17 12:21:26 +01009067 }
willy tarreau41310e72006-03-25 18:17:56 +01009068
9069 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01009070}
9071
willy tarreaub952e1d2005-12-18 01:31:20 +01009072int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01009073
9074 appsess *temp1,*temp2;
9075 temp1 = (appsess *)key1;
9076 temp2 = (appsess *)key2;
9077
9078 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
9079 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
9080
9081 return (strcmp(temp1->sessid,temp2->sessid) == 0);
9082}/* end match_str */
9083
willy tarreaub952e1d2005-12-18 01:31:20 +01009084void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01009085 appsess *temp1;
9086
9087 //printf("destroy called\n");
9088 temp1 = (appsess *)data;
9089
9090 if (temp1->sessid)
9091 pool_free_to(apools.sessid, temp1->sessid);
9092
9093 if (temp1->serverid)
9094 pool_free_to(apools.serverid, temp1->serverid);
9095
9096 pool_free(appsess, temp1);
9097} /* end destroy */
9098
9099void appsession_cleanup( void )
9100{
9101 struct proxy *p = proxy;
9102
9103 while(p) {
9104 chtbl_destroy(&(p->htbl_proxy));
9105 p = p->next;
9106 }
9107}/* end appsession_cleanup() */
9108
9109void pool_destroy(void **pool)
9110{
9111 void *temp, *next;
9112 next = pool;
9113 while (next) {
9114 temp = next;
9115 next = *(void **)temp;
9116 free(temp);
9117 }
9118}/* end pool_destroy() */
9119
willy tarreaub952e1d2005-12-18 01:31:20 +01009120void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01009121 struct proxy *p = proxy;
9122 struct cap_hdr *h,*h_next;
9123 struct server *s,*s_next;
9124 struct listener *l,*l_next;
9125
9126 while (p) {
9127 if (p->id)
9128 free(p->id);
9129
9130 if (p->check_req)
9131 free(p->check_req);
9132
9133 if (p->cookie_name)
9134 free(p->cookie_name);
9135
9136 if (p->capture_name)
9137 free(p->capture_name);
9138
9139 /* only strup if the user have set in config.
9140 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01009141 if (p->errmsg.msg400) free(p->errmsg.msg400);
9142 if (p->errmsg.msg403) free(p->errmsg.msg403);
9143 if (p->errmsg.msg408) free(p->errmsg.msg408);
9144 if (p->errmsg.msg500) free(p->errmsg.msg500);
9145 if (p->errmsg.msg502) free(p->errmsg.msg502);
9146 if (p->errmsg.msg503) free(p->errmsg.msg503);
9147 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01009148 */
9149 if (p->appsession_name)
9150 free(p->appsession_name);
9151
9152 h = p->req_cap;
9153 while (h) {
9154 h_next = h->next;
9155 if (h->name)
9156 free(h->name);
9157 pool_destroy(h->pool);
9158 free(h);
9159 h = h_next;
9160 }/* end while(h) */
9161
9162 h = p->rsp_cap;
9163 while (h) {
9164 h_next = h->next;
9165 if (h->name)
9166 free(h->name);
9167
9168 pool_destroy(h->pool);
9169 free(h);
9170 h = h_next;
9171 }/* end while(h) */
9172
9173 s = p->srv;
9174 while (s) {
9175 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01009176 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01009177 free(s->id);
9178
willy tarreaub952e1d2005-12-18 01:31:20 +01009179 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01009180 free(s->cookie);
9181
9182 free(s);
9183 s = s_next;
9184 }/* end while(s) */
9185
9186 l = p->listen;
9187 while (l) {
9188 l_next = l->next;
9189 free(l);
9190 l = l_next;
9191 }/* end while(l) */
9192
9193 pool_destroy((void **) p->req_cap_pool);
9194 pool_destroy((void **) p->rsp_cap_pool);
9195 p = p->next;
9196 }/* end while(p) */
9197
9198 if (global.chroot) free(global.chroot);
9199 if (global.pidfile) free(global.pidfile);
9200
willy tarreau12350152005-12-18 01:03:27 +01009201 if (StaticReadEvent) free(StaticReadEvent);
9202 if (StaticWriteEvent) free(StaticWriteEvent);
9203 if (fdtab) free(fdtab);
9204
9205 pool_destroy(pool_session);
9206 pool_destroy(pool_buffer);
9207 pool_destroy(pool_fdtab);
9208 pool_destroy(pool_requri);
9209 pool_destroy(pool_task);
9210 pool_destroy(pool_capture);
9211 pool_destroy(pool_appsess);
9212
9213 if (have_appsession) {
9214 pool_destroy(apools.serverid);
9215 pool_destroy(apools.sessid);
9216 }
9217} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01009218
willy tarreau41310e72006-03-25 18:17:56 +01009219/* sends the signal <sig> to all pids found in <oldpids> */
9220static void tell_old_pids(int sig) {
9221 int p;
9222 for (p = 0; p < nb_oldpids; p++)
9223 kill(oldpids[p], sig);
9224}
9225
willy tarreau0f7af912005-12-17 12:21:26 +01009226int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01009227 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01009228 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009229 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009230 init(argc, argv);
9231
willy tarreau0f7af912005-12-17 12:21:26 +01009232 signal(SIGQUIT, dump);
9233 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01009234 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01009235#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01009236 signal(SIGINT, sig_int);
9237 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01009238#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009239
9240 /* on very high loads, a sigpipe sometimes happen just between the
9241 * getsockopt() which tells "it's OK to write", and the following write :-(
9242 */
willy tarreau3242e862005-12-17 12:27:53 +01009243#ifndef MSG_NOSIGNAL
9244 signal(SIGPIPE, SIG_IGN);
9245#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009246
willy tarreau41310e72006-03-25 18:17:56 +01009247 /* We will loop at most 100 times with 10 ms delay each time.
9248 * That's at most 1 second. We only send a signal to old pids
9249 * if we cannot grab at least one port.
9250 */
9251 retry = MAX_START_RETRIES;
9252 err = ERR_NONE;
9253 while (retry >= 0) {
9254 struct timeval w;
9255 err = start_proxies(retry == 0 || nb_oldpids == 0);
9256 if (err != ERR_RETRYABLE)
9257 break;
9258 if (nb_oldpids == 0)
9259 break;
9260
9261 tell_old_pids(SIGTTOU);
9262 /* give some time to old processes to stop listening */
9263 w.tv_sec = 0;
9264 w.tv_usec = 10*1000;
9265 select(0, NULL, NULL, NULL, &w);
9266 retry--;
9267 }
9268
9269 /* Note: start_proxies() sends an alert when it fails. */
9270 if (err != ERR_NONE) {
9271 if (retry != MAX_START_RETRIES && nb_oldpids)
9272 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01009273 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01009274 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009275
9276 if (listeners == 0) {
9277 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009278 /* Note: we don't have to send anything to the old pids because we
9279 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01009280 exit(1);
9281 }
9282
willy tarreaudbd3bef2006-01-20 19:35:18 +01009283 /* prepare pause/play signals */
9284 signal(SIGTTOU, sig_pause);
9285 signal(SIGTTIN, sig_listen);
9286
Willy TARREAUe3283d12006-03-01 22:15:29 +01009287 if (global.mode & MODE_DAEMON) {
9288 global.mode &= ~MODE_VERBOSE;
9289 global.mode |= MODE_QUIET;
9290 }
9291
willy tarreaud0fb4652005-12-18 01:32:04 +01009292 /* MODE_QUIET can inhibit alerts and warnings below this line */
9293
9294 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01009295 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01009296 /* detach from the tty */
9297 fclose(stdin); fclose(stdout); fclose(stderr);
9298 close(0); close(1); close(2);
9299 }
willy tarreau0f7af912005-12-17 12:21:26 +01009300
willy tarreaufe2c5c12005-12-17 14:14:34 +01009301 /* open log & pid files before the chroot */
9302 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
9303 int pidfd;
9304 unlink(global.pidfile);
9305 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
9306 if (pidfd < 0) {
9307 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01009308 if (nb_oldpids)
9309 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01009310 exit(1);
9311 }
9312 pidfile = fdopen(pidfd, "w");
9313 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009314
9315 /* chroot if needed */
9316 if (global.chroot != NULL) {
9317 if (chroot(global.chroot) == -1) {
9318 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01009319 if (nb_oldpids)
9320 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01009321 }
9322 chdir("/");
9323 }
9324
willy tarreaub1285d52005-12-18 01:20:14 +01009325 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01009326 if (!global.rlimit_nofile)
9327 global.rlimit_nofile = global.maxsock;
9328
willy tarreaub1285d52005-12-18 01:20:14 +01009329 if (global.rlimit_nofile) {
9330 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
9331 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
9332 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
9333 }
willy tarreau746e26b2006-03-25 11:14:35 +01009334 }
9335
9336 if (global.rlimit_memmax) {
9337 limit.rlim_cur = limit.rlim_max =
9338 global.rlimit_memmax * 1048576 / global.nbproc;
9339#ifdef RLIMIT_AS
9340 if (setrlimit(RLIMIT_AS, &limit) == -1) {
9341 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9342 argv[0], global.rlimit_memmax);
9343 }
9344#else
9345 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
9346 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9347 argv[0], global.rlimit_memmax);
9348 }
9349#endif
willy tarreaub1285d52005-12-18 01:20:14 +01009350 }
9351
willy tarreau41310e72006-03-25 18:17:56 +01009352 if (nb_oldpids)
9353 tell_old_pids(oldpids_sig);
9354
9355 /* Note that any error at this stage will be fatal because we will not
9356 * be able to restart the old pids.
9357 */
9358
willy tarreau9fe663a2005-12-17 13:02:59 +01009359 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01009360 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009361 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
9362 exit(1);
9363 }
9364
willy tarreau036e1ce2005-12-17 13:46:33 +01009365 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009366 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
9367 exit(1);
9368 }
9369
willy tarreaub1285d52005-12-18 01:20:14 +01009370 /* check ulimits */
9371 limit.rlim_cur = limit.rlim_max = 0;
9372 getrlimit(RLIMIT_NOFILE, &limit);
9373 if (limit.rlim_cur < global.maxsock) {
9374 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",
9375 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
9376 }
9377
willy tarreau9fe663a2005-12-17 13:02:59 +01009378 if (global.mode & MODE_DAEMON) {
9379 int ret = 0;
9380 int proc;
9381
9382 /* the father launches the required number of processes */
9383 for (proc = 0; proc < global.nbproc; proc++) {
9384 ret = fork();
9385 if (ret < 0) {
9386 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009387 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01009388 exit(1); /* there has been an error */
9389 }
9390 else if (ret == 0) /* child breaks here */
9391 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009392 if (pidfile != NULL) {
9393 fprintf(pidfile, "%d\n", ret);
9394 fflush(pidfile);
9395 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009396 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01009397 /* close the pidfile both in children and father */
9398 if (pidfile != NULL)
9399 fclose(pidfile);
9400 free(global.pidfile);
9401
willy tarreau9fe663a2005-12-17 13:02:59 +01009402 if (proc == global.nbproc)
9403 exit(0); /* parent must leave */
9404
willy tarreau750a4722005-12-17 13:21:24 +01009405 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
9406 * that we can detach from the TTY. We MUST NOT do it in other cases since
9407 * it would have already be done, and 0-2 would have been affected to listening
9408 * sockets
9409 */
9410 if (!(global.mode & MODE_QUIET)) {
9411 /* detach from the tty */
9412 fclose(stdin); fclose(stdout); fclose(stderr);
9413 close(0); close(1); close(2); /* close all fd's */
9414 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
9415 }
willy tarreaua1598082005-12-17 13:08:06 +01009416 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01009417 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01009418 }
9419
willy tarreau1c2ad212005-12-18 01:11:29 +01009420#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009421 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009422 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
9423 epoll_loop(POLL_LOOP_ACTION_RUN);
9424 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009425 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009426 }
9427 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01009428 Warning("epoll() is not available. Using poll()/select() instead.\n");
9429 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009430 }
9431 }
9432#endif
9433
9434#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009435 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009436 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
9437 poll_loop(POLL_LOOP_ACTION_RUN);
9438 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009439 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009440 }
9441 else {
9442 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01009443 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009444 }
9445 }
9446#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01009447 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009448 if (select_loop(POLL_LOOP_ACTION_INIT)) {
9449 select_loop(POLL_LOOP_ACTION_RUN);
9450 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009451 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01009452 }
9453 }
9454
willy tarreau0f7af912005-12-17 12:21:26 +01009455
willy tarreau12350152005-12-18 01:03:27 +01009456 /* Free all Hash Keys and all Hash elements */
9457 appsession_cleanup();
9458 /* Do some cleanup */
9459 deinit();
9460
willy tarreau0f7af912005-12-17 12:21:26 +01009461 exit(0);
9462}
willy tarreau12350152005-12-18 01:03:27 +01009463
9464#if defined(DEBUG_HASH)
9465static void print_table(const CHTbl *htbl) {
9466
9467 ListElmt *element;
9468 int i;
9469 appsess *asession;
9470
9471 /*****************************************************************************
9472 * *
9473 * Display the chained hash table. *
9474 * *
9475 *****************************************************************************/
9476
9477 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
9478
9479 for (i = 0; i < TBLSIZ; i++) {
9480 fprintf(stdout, "Bucket[%03d]\n", i);
9481
9482 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9483 //fprintf(stdout, "%c", *(char *)list_data(element));
9484 asession = (appsess *)list_data(element);
9485 fprintf(stdout, "ELEM :%s:", asession->sessid);
9486 fprintf(stdout, " Server :%s: \n", asession->serverid);
9487 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
9488 }
9489
9490 fprintf(stdout, "\n");
9491 }
9492 return;
9493} /* end print_table */
9494#endif
9495
9496static int appsession_init(void)
9497{
9498 static int initialized = 0;
9499 int idlen;
9500 struct server *s;
9501 struct proxy *p = proxy;
9502
9503 if (!initialized) {
9504 if (!appsession_task_init()) {
9505 apools.sessid = NULL;
9506 apools.serverid = NULL;
9507 apools.ser_waste = 0;
9508 apools.ser_use = 0;
9509 apools.ser_msize = sizeof(void *);
9510 apools.ses_waste = 0;
9511 apools.ses_use = 0;
9512 apools.ses_msize = sizeof(void *);
9513 while (p) {
9514 s = p->srv;
9515 if (apools.ses_msize < p->appsession_len)
9516 apools.ses_msize = p->appsession_len;
9517 while (s) {
9518 idlen = strlen(s->id);
9519 if (apools.ser_msize < idlen)
9520 apools.ser_msize = idlen;
9521 s = s->next;
9522 }
9523 p = p->next;
9524 }
9525 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
9526 apools.ses_msize ++;
9527 }
9528 else {
9529 fprintf(stderr, "appsession_task_init failed\n");
9530 return -1;
9531 }
9532 initialized ++;
9533 }
9534 return 0;
9535}
9536
9537static int appsession_task_init(void)
9538{
9539 static int initialized = 0;
9540 struct task *t;
9541 if (!initialized) {
9542 if ((t = pool_alloc(task)) == NULL)
9543 return -1;
9544 t->next = t->prev = t->rqnext = NULL;
willy tarreau5e698ef2006-05-02 14:51:00 +02009545 t->wq = LIST_HEAD(wait_queue[0]);
willy tarreau12350152005-12-18 01:03:27 +01009546 t->state = TASK_IDLE;
9547 t->context = NULL;
9548 tv_delayfrom(&t->expire, &now, TBLCHKINT);
9549 task_queue(t);
9550 t->process = appsession_refresh;
9551 initialized ++;
9552 }
9553 return 0;
9554}
9555
9556static int appsession_refresh(struct task *t) {
9557 struct proxy *p = proxy;
9558 CHTbl *htbl;
9559 ListElmt *element, *last;
9560 int i;
9561 appsess *asession;
9562 void *data;
9563
9564 while (p) {
9565 if (p->appsession_name != NULL) {
9566 htbl = &p->htbl_proxy;
9567 /* if we ever give up the use of TBLSIZ, we need to change this */
9568 for (i = 0; i < TBLSIZ; i++) {
9569 last = NULL;
9570 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9571 asession = (appsess *)list_data(element);
9572 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
9573 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
9574 int len;
9575 /*
9576 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
9577 */
9578 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
9579 asession->sessid, asession->serverid?asession->serverid:"(null)");
9580 write(1, trash, len);
9581 }
9582 /* delete the expired element from within the hash table */
9583 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
9584 && (htbl->table[i].destroy != NULL)) {
9585 htbl->table[i].destroy(data);
9586 }
9587 if (last == NULL) {/* patient lost his head, get a new one */
9588 element = list_head(&htbl->table[i]);
9589 if (element == NULL) break; /* no heads left, go to next patient */
9590 }
9591 else
9592 element = last;
9593 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
9594 else
9595 last = element;
9596 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
9597 }
9598 }
9599 p = p->next;
9600 }
9601 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
9602 return TBLCHKINT;
9603} /* end appsession_refresh */
9604
willy tarreau18a957c2006-04-12 19:26:23 +02009605
9606/*
9607 * Local variables:
9608 * c-indent-level: 4
9609 * c-basic-offset: 4
9610 * End:
9611 */