blob: c6a03125bf24f5c870c5c7f0ebbeb59583d5f5bc [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 tarreau9e138862006-05-14 23:06:28 +020088#include <include/base64.h>
89#include <include/uri_auth.h>
willy tarreau598da412005-12-18 01:07:29 +010090#include "include/appsession.h"
willy tarreau18a957c2006-04-12 19:26:23 +020091#include "include/mini-clist.h"
willy tarreau12350152005-12-18 01:03:27 +010092
willy tarreaubfad5742006-03-23 14:19:11 +010093#ifndef HAPROXY_VERSION
Willy TARREAU4404b7e2006-05-14 10:00:09 +020094#define HAPROXY_VERSION "1.2.13.1"
willy tarreaubfad5742006-03-23 14:19:11 +010095#endif
96
97#ifndef HAPROXY_DATE
Willy TARREAU4404b7e2006-05-14 10:00:09 +020098#define HAPROXY_DATE "2006/05/14"
willy tarreaubfad5742006-03-23 14:19:11 +010099#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100100
101/* this is for libc5 for example */
102#ifndef TCP_NODELAY
103#define TCP_NODELAY 1
104#endif
105
106#ifndef SHUT_RD
107#define SHUT_RD 0
108#endif
109
110#ifndef SHUT_WR
111#define SHUT_WR 1
112#endif
113
willy tarreau0174f312005-12-18 01:02:42 +0100114/*
115 * BUFSIZE defines the size of a read and write buffer. It is the maximum
116 * amount of bytes which can be stored by the proxy for each session. However,
117 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
118 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
119 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
120 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
121 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
122 */
123#ifndef BUFSIZE
124#define BUFSIZE 16384
125#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100126
127// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100128#ifndef MAXREWRITE
129#define MAXREWRITE (BUFSIZE / 2)
130#endif
131
willy tarreau9fe663a2005-12-17 13:02:59 +0100132#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100133#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100134
willy tarreau5cbea6f2005-12-17 12:48:26 +0100135// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100136#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100137
willy tarreaue39cd132005-12-17 13:00:18 +0100138// max # of added headers per request
139#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100140
141// max # of matches per regexp
142#define MAX_MATCH 10
143
willy tarreau0174f312005-12-18 01:02:42 +0100144// cookie delimitor in "prefix" mode. This character is inserted between the
145// persistence cookie and the original value. The '~' is allowed by RFC2965,
146// and should not be too common in server names.
147#ifndef COOKIE_DELIM
148#define COOKIE_DELIM '~'
149#endif
150
willy tarreau0f7af912005-12-17 12:21:26 +0100151#define CONN_RETRIES 3
152
willy tarreau5cbea6f2005-12-17 12:48:26 +0100153#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100154#define DEF_CHKINTR 2000
155#define DEF_FALLTIME 3
156#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100157#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100158
Willy TARREAU13032e72006-03-12 17:31:45 +0100159/* Default connections limit.
160 *
161 * A system limit can be enforced at build time in order to avoid using haproxy
162 * beyond reasonable system limits. For this, just define SYSTEM_MAXCONN to the
163 * absolute limit accepted by the system. If the configuration specifies a
164 * higher value, it will be capped to SYSTEM_MAXCONN and a warning will be
165 * emitted. The only way to override this limit will be to set it via the
166 * command-line '-n' argument.
167 */
168#ifndef SYSTEM_MAXCONN
willy tarreau9fe663a2005-12-17 13:02:59 +0100169#define DEFAULT_MAXCONN 2000
Willy TARREAU13032e72006-03-12 17:31:45 +0100170#else
171#define DEFAULT_MAXCONN SYSTEM_MAXCONN
172#endif
willy tarreau9fe663a2005-12-17 13:02:59 +0100173
willy tarreaue0331262006-05-15 03:02:46 +0200174#ifdef CONFIG_PRODUCT_NAME
175#define PRODUCT_NAME CONFIG_PRODUCT_NAME
176#else
177#define PRODUCT_NAME "HAProxy"
178#endif
179
willy tarreau0f7af912005-12-17 12:21:26 +0100180/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
181#define INTBITS 5
182
183/* show stats this every millisecond, 0 to disable */
184#ifndef STATTIME
185#define STATTIME 2000
186#endif
187
willy tarreau5cbea6f2005-12-17 12:48:26 +0100188/* this reduces the number of calls to select() by choosing appropriate
189 * sheduler precision in milliseconds. It should be near the minimum
190 * time that is needed by select() to collect all events. All timeouts
191 * are rounded up by adding this value prior to pass it to select().
192 */
193#define SCHEDULER_RESOLUTION 9
194
willy tarreaub952e1d2005-12-18 01:31:20 +0100195#define TIME_ETERNITY -1
196/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100197#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
198#define SETNOW(a) (*a=now)
199
willy tarreau9da061b2005-12-17 12:29:56 +0100200/****** string-specific macros and functions ******/
201/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
202#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
203
204/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
205#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
206
willy tarreau0174f312005-12-18 01:02:42 +0100207/* returns 1 only if only zero or one bit is set in X, which means that X is a
208 * power of 2, and 0 otherwise */
209#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100210/*
211 * copies at most <size-1> chars from <src> to <dst>. Last char is always
212 * set to 0, unless <size> is 0. The number of chars copied is returned
213 * (excluding the terminating zero).
214 * This code has been optimized for size and speed : on x86, it's 45 bytes
215 * long, uses only registers, and consumes only 4 cycles per char.
216 */
willy tarreau750a4722005-12-17 13:21:24 +0100217int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100218 char *orig = dst;
219 if (size) {
220 while (--size && (*dst = *src)) {
221 src++; dst++;
222 }
223 *dst = 0;
224 }
225 return dst - orig;
226}
willy tarreau9da061b2005-12-17 12:29:56 +0100227
willy tarreau4302f492005-12-18 01:00:37 +0100228/*
willy tarreaucb406512006-05-18 00:52:35 +0200229 * This function simply returns a statically allocated string containing
230 * the ascii representation for number 'n' in decimal.
231 */
232char *ultoa(unsigned long n) {
233 /* enough to store 2^63=18446744073709551615 */
234 static char itoa_str[21];
235 char *pos;
236
237 pos = itoa_str + sizeof(itoa_str) - 1;
238 *pos-- = '\0';
239
240 do {
241 *pos-- = '0' + n % 10;
242 n /= 10;
243 } while (n && pos >= itoa_str);
244 return pos + 1;
245}
246
247/*
willy tarreau4302f492005-12-18 01:00:37 +0100248 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
249 * dynamically allocated. In the first case, <__pool> is updated to point to
250 * the next element in the list.
251 */
252#define pool_alloc_from(__pool, __len) ({ \
253 void *__p; \
254 if ((__p = (__pool)) == NULL) \
255 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
256 else { \
257 __pool = *(void **)(__pool); \
258 } \
259 __p; \
260})
261
262/*
263 * Puts a memory area back to the corresponding pool.
264 * Items are chained directly through a pointer that
265 * is written in the beginning of the memory area, so
266 * there's no need for any carrier cell. This implies
267 * that each memory area is at least as big as one
268 * pointer.
269 */
270#define pool_free_to(__pool, __ptr) ({ \
271 *(void **)(__ptr) = (void *)(__pool); \
272 __pool = (void *)(__ptr); \
273})
274
275
willy tarreau0f7af912005-12-17 12:21:26 +0100276#define MEM_OPTIM
277#ifdef MEM_OPTIM
278/*
279 * Returns a pointer to type <type> taken from the
280 * pool <pool_type> or dynamically allocated. In the
281 * first case, <pool_type> is updated to point to the
282 * next element in the list.
283 */
284#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100285 void *__p; \
286 if ((__p = pool_##type) == NULL) \
287 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100288 else { \
289 pool_##type = *(void **)pool_##type; \
290 } \
willy tarreau4302f492005-12-18 01:00:37 +0100291 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100292})
293
294/*
295 * Puts a memory area back to the corresponding pool.
296 * Items are chained directly through a pointer that
297 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100298 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100299 * that each memory area is at least as big as one
300 * pointer.
301 */
302#define pool_free(type, ptr) ({ \
303 *(void **)ptr = (void *)pool_##type; \
304 pool_##type = (void *)ptr; \
305})
306
307#else
308#define pool_alloc(type) (calloc(1,sizeof_##type));
309#define pool_free(type, ptr) (free(ptr));
310#endif /* MEM_OPTIM */
311
willy tarreau5cbea6f2005-12-17 12:48:26 +0100312#define sizeof_task sizeof(struct task)
313#define sizeof_session sizeof(struct session)
willy tarreau18a957c2006-04-12 19:26:23 +0200314#define sizeof_pendconn sizeof(struct pendconn)
willy tarreau0f7af912005-12-17 12:21:26 +0100315#define sizeof_buffer sizeof(struct buffer)
316#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100317#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100318#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100319#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100320#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100321
willy tarreau5cbea6f2005-12-17 12:48:26 +0100322/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100323#define FD_STCLOSE 0
324#define FD_STLISTEN 1
325#define FD_STCONN 2
326#define FD_STREADY 3
327#define FD_STERROR 4
328
willy tarreau5cbea6f2005-12-17 12:48:26 +0100329/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100330#define TASK_IDLE 0
331#define TASK_RUNNING 1
332
willy tarreau5cbea6f2005-12-17 12:48:26 +0100333/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100334#define PR_STNEW 0
335#define PR_STIDLE 1
336#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100337#define PR_STSTOPPED 3
338#define PR_STPAUSED 4
willy tarreaufac1a862006-05-21 10:20:28 +0200339#define PR_STERROR 5
willy tarreau0f7af912005-12-17 12:21:26 +0100340
willy tarreau5cbea6f2005-12-17 12:48:26 +0100341/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100342#define PR_MODE_TCP 0
343#define PR_MODE_HTTP 1
344#define PR_MODE_HEALTH 2
345
willy tarreau1c2ad212005-12-18 01:11:29 +0100346/* possible actions for the *poll() loops */
347#define POLL_LOOP_ACTION_INIT 0
348#define POLL_LOOP_ACTION_RUN 1
349#define POLL_LOOP_ACTION_CLEAN 2
350
willy tarreau64a3cc32005-12-18 01:13:11 +0100351/* poll mechanisms available */
352#define POLL_USE_SELECT (1<<0)
353#define POLL_USE_POLL (1<<1)
354#define POLL_USE_EPOLL (1<<2)
355
willy tarreau5cbea6f2005-12-17 12:48:26 +0100356/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100357#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
358#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
359#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
360#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
361#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
362#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
363#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
364#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau0174f312005-12-18 01:02:42 +0100365#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
366#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
367#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
368#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
369#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
370#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
371#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
372#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
373#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
374#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
375#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100376#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
377#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100378#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100379#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau1a3442d2006-03-24 21:03:20 +0100380#define PR_O_BALANCE_SH 0x00400000 /* balance on source IP hash */
381#define PR_O_BALANCE (PR_O_BALANCE_RR | PR_O_BALANCE_SH)
willy tarreau03a92de2006-05-21 18:26:53 +0200382#define PR_O_ABRT_CLOSE 0x00800000 /* immediately abort request when client closes */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100383
willy tarreaua5e8c662006-04-29 10:43:46 +0200384/* various session flags, bits values 0x01 to 0x20 (shift 0) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100385#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
386#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
387#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
388#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
389#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
390#define SN_POST 0x00000020 /* the request was an HTTP POST */
391
willy tarreaua5e8c662006-04-29 10:43:46 +0200392/* session flags dedicated to cookies : bits values 0x40, 0x80 (0-3 shift 6) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100393#define SN_CK_NONE 0x00000000 /* this session had no cookie */
394#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
395#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
396#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
397#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
398#define SN_CK_SHIFT 6 /* bit shift */
399
willy tarreaua5e8c662006-04-29 10:43:46 +0200400/* session termination conditions, bits values 0x100 to 0x700 (0-7 shift 8) */
willy tarreaub1285d52005-12-18 01:20:14 +0100401#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100402#define SN_ERR_CLITO 0x00000100 /* client time-out */
403#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
404#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
405#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
406#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100407#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
408#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100409#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
410#define SN_ERR_SHIFT 8 /* bit shift */
411
willy tarreaua5e8c662006-04-29 10:43:46 +0200412/* session state at termination, bits values 0x1000 to 0x7000 (0-7 shift 12) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100413#define SN_FINST_R 0x00001000 /* session ended during client request */
414#define SN_FINST_C 0x00002000 /* session ended during server connect */
415#define SN_FINST_H 0x00003000 /* session ended during server headers */
416#define SN_FINST_D 0x00004000 /* session ended during data phase */
417#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
willy tarreau078c79a2006-05-13 12:23:58 +0200418#define SN_FINST_Q 0x00006000 /* session ended while waiting in queue for a server slot */
willy tarreau036e1ce2005-12-17 13:46:33 +0100419#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
420#define SN_FINST_SHIFT 12 /* bit shift */
421
willy tarreaua5e8c662006-04-29 10:43:46 +0200422/* cookie information, bits values 0x10000 to 0x80000 (0-8 shift 16) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100423#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
424#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
425#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
426#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
427#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100428#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100429#define SN_SCK_SHIFT 16 /* bit shift */
430
willy tarreaua5e8c662006-04-29 10:43:46 +0200431/* cacheability management, bits values 0x100000 to 0x300000 (0-3 shift 20) */
willy tarreau97f58572005-12-18 00:53:44 +0100432#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
433#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
434#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100435
willy tarreaua5e8c662006-04-29 10:43:46 +0200436/* various other session flags, bits values 0x400000 and above */
437#define SN_MONITOR 0x00400000 /* this session comes from a monitoring system */
willy tarreaudfece232006-05-02 00:19:57 +0200438#define SN_ASSIGNED 0x00800000 /* no need to assign a server to this session */
439#define SN_ADDR_SET 0x01000000 /* this session's server address has been set */
willy tarreaue0331262006-05-15 03:02:46 +0200440#define SN_SELF_GEN 0x02000000 /* the proxy generates data for the client (eg: stats) */
willy tarreaua5e8c662006-04-29 10:43:46 +0200441
willy tarreaue0331262006-05-15 03:02:46 +0200442/* various data sources for the responses */
443#define DATA_SRC_NONE 0
444#define DATA_SRC_STATS 1
willy tarreaua5e8c662006-04-29 10:43:46 +0200445
willy tarreau1f431b52006-05-21 14:46:15 +0200446/* data transmission states for the responses */
447#define DATA_ST_INIT 0
448#define DATA_ST_DATA 1
449
willy tarreau5cbea6f2005-12-17 12:48:26 +0100450/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100451#define CL_STHEADERS 0
452#define CL_STDATA 1
453#define CL_STSHUTR 2
454#define CL_STSHUTW 3
455#define CL_STCLOSE 4
456
willy tarreau5cbea6f2005-12-17 12:48:26 +0100457/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100458#define SV_STIDLE 0
willy tarreau9fea1942006-05-12 19:46:40 +0200459#define SV_STCONN 1
460#define SV_STHEADERS 2
461#define SV_STDATA 3
462#define SV_STSHUTR 4
463#define SV_STSHUTW 5
464#define SV_STCLOSE 6
willy tarreau0f7af912005-12-17 12:21:26 +0100465
466/* result of an I/O event */
467#define RES_SILENT 0 /* didn't happen */
468#define RES_DATA 1 /* data were sent or received */
469#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
470#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
471
willy tarreau9fe663a2005-12-17 13:02:59 +0100472/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100473#define MODE_DEBUG 1
474#define MODE_STATS 2
475#define MODE_LOG 4
476#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100477#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100478#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100479#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100480#define MODE_STARTING 128
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100481#define MODE_FOREGROUND 256
willy tarreau5cbea6f2005-12-17 12:48:26 +0100482
483/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100484#define SRV_RUNNING 1 /* the server is UP */
485#define SRV_BACKUP 2 /* this server is a backup server */
486#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100487#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100488#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100489
willy tarreaudfece232006-05-02 00:19:57 +0200490/* function which act on servers need to return various errors */
491#define SRV_STATUS_OK 0 /* everything is OK. */
492#define SRV_STATUS_INTERNAL 1 /* other unrecoverable errors. */
493#define SRV_STATUS_NOSRV 2 /* no server is available */
494#define SRV_STATUS_FULL 3 /* the/all server(s) are saturated */
495#define SRV_STATUS_QUEUED 4 /* the/all server(s) are saturated but the connection was queued */
496
willy tarreaue39cd132005-12-17 13:00:18 +0100497/* what to do when a header matches a regex */
498#define ACT_ALLOW 0 /* allow the request */
499#define ACT_REPLACE 1 /* replace the matching header */
500#define ACT_REMOVE 2 /* remove the matching header */
501#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100502#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100503
willy tarreau9fe663a2005-12-17 13:02:59 +0100504/* configuration sections */
505#define CFG_NONE 0
506#define CFG_GLOBAL 1
507#define CFG_LISTEN 2
508
willy tarreaua1598082005-12-17 13:08:06 +0100509/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100510#define LW_DATE 1 /* date */
511#define LW_CLIP 2 /* CLient IP */
512#define LW_SVIP 4 /* SerVer IP */
513#define LW_SVID 8 /* server ID */
514#define LW_REQ 16 /* http REQuest */
515#define LW_RESP 32 /* http RESPonse */
516#define LW_PXIP 64 /* proxy IP */
517#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100518#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100519#define LW_COOKIE 512 /* captured cookie */
520#define LW_REQHDR 1024 /* request header(s) */
521#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100522
willy tarreau41310e72006-03-25 18:17:56 +0100523#define ERR_NONE 0 /* no error */
524#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
525#define ERR_FATAL 2 /* fatal error, may be cumulated */
526
willy tarreau0f7af912005-12-17 12:21:26 +0100527/*********************************************************************/
528
529#define LIST_HEAD(a) ((void *)(&(a)))
530
531/*********************************************************************/
532
willy tarreau9e138862006-05-14 23:06:28 +0200533/* describes a chunk of string */
534struct chunk {
535 char *str; /* beginning of the string itself. Might not be 0-terminated */
536 int len; /* size of the string from first to last char. <0 = uninit. */
537};
538
willy tarreau4302f492005-12-18 01:00:37 +0100539struct cap_hdr {
540 struct cap_hdr *next;
541 char *name; /* header name, case insensitive */
542 int namelen; /* length of the header name, to speed-up lookups */
543 int len; /* capture length, not including terminal zero */
544 int index; /* index in the output array */
545 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
546};
547
willy tarreau0f7af912005-12-17 12:21:26 +0100548struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100549 struct hdr_exp *next;
550 regex_t *preg; /* expression to look for */
551 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
552 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100553};
554
555struct buffer {
556 unsigned int l; /* data length */
557 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100558 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100559 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100560 char data[BUFSIZE];
561};
562
willy tarreau18a957c2006-04-12 19:26:23 +0200563struct pendconn {
564 struct list list; /* chaining ... */
565 struct session *sess; /* the session waiting for a connection */
566 struct server *srv; /* the server we are waiting for */
567};
568
willy tarreau0f7af912005-12-17 12:21:26 +0100569struct server {
570 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100571 int state; /* server state (SRV_*) */
572 int cklen; /* the len of the cookie, to speed up checks */
573 char *cookie; /* the id set in the cookie */
574 char *id; /* just for identification */
willy tarreau18a957c2006-04-12 19:26:23 +0200575 struct list pendconns; /* pending connections */
willy tarreaucb406512006-05-18 00:52:35 +0200576 int nbpend, nbpend_max; /* number of pending connections */
willy tarreau59a6cc22006-05-12 01:29:08 +0200577 struct task *queue_mgt; /* the task associated to the queue processing */
willy tarreau0f7af912005-12-17 12:21:26 +0100578 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100579 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100580 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100581 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100582 int rise, fall; /* time in iterations */
583 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100584 int result; /* 0 = connect OK, -1 = connect KO */
585 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreaue3f023f2006-04-08 21:52:24 +0200586 unsigned char uweight, eweight; /* user-specified weight-1, and effective weight-1 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200587 unsigned int wscore; /* weight score, used during srv map computation */
willy tarreaucb406512006-05-18 00:52:35 +0200588 int cur_sess, cur_sess_max; /* number of currently active sessions (including syn_sent) */
willy tarreaua647c702006-04-15 22:45:52 +0200589 unsigned int cum_sess; /* cumulated number of sessions really sent to this server */
willy tarreau18a957c2006-04-12 19:26:23 +0200590 unsigned int maxconn; /* max # of active sessions. 0 = unlimited. */
willy tarreaucb406512006-05-18 00:52:35 +0200591 unsigned failed_checks, down_trans; /* failed checks and up-down transitions */
willy tarreaue3b30652006-05-21 16:23:22 +0200592 unsigned failed_conns, failed_resp; /* failed connect() and responses */
593 unsigned failed_secu; /* blocked responses because of security concerns */
willy tarreau535ae7a2005-12-17 12:58:00 +0100594 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100595};
596
willy tarreau5cbea6f2005-12-17 12:48:26 +0100597/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100598struct task {
599 struct task *next, *prev; /* chaining ... */
600 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100601 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100602 int state; /* task state : IDLE or RUNNING */
603 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100604 int (*process)(struct task *t); /* the function which processes the task */
605 void *context; /* the task's context */
606};
607
608/* WARNING: if new fields are added, they must be initialized in event_accept() */
609struct session {
610 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100611 /* application specific below */
612 struct timeval crexpire; /* expiration date for a client read */
613 struct timeval cwexpire; /* expiration date for a client write */
614 struct timeval srexpire; /* expiration date for a server read */
615 struct timeval swexpire; /* expiration date for a server write */
616 struct timeval cnexpire; /* expiration date for a connect */
617 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
618 struct proxy *proxy; /* the proxy this socket belongs to */
619 int cli_fd; /* the client side fd */
620 int srv_fd; /* the server side fd */
621 int cli_state; /* state of the client side */
622 int srv_state; /* state of the server side */
623 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100624 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100625 struct buffer *req; /* request buffer */
626 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100627 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100628 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100629 struct server *srv; /* the server being used */
willy tarreau18a957c2006-04-12 19:26:23 +0200630 struct pendconn *pend_pos; /* if not NULL, points to the position in the pending queue */
willy tarreau4302f492005-12-18 01:00:37 +0100631 char **req_cap; /* array of captured request headers (may be NULL) */
632 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreau9e138862006-05-14 23:06:28 +0200633 struct chunk req_line; /* points to first line */
634 struct chunk auth_hdr; /* points to 'Authorization:' header */
willy tarreaua1598082005-12-17 13:08:06 +0100635 struct {
636 int logwait; /* log fields waiting to be collected : LW_* */
637 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
638 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
willy tarreauf32f5242006-05-02 22:54:52 +0200639 long t_queue; /* delay before the session gets out of the connect queue, -1 if never occurs */
willy tarreaua1598082005-12-17 13:08:06 +0100640 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
641 long t_data; /* delay before the first data byte from the server ... */
642 unsigned long t_close; /* total session duration */
willy tarreau5e69b162006-05-12 19:49:37 +0200643 unsigned long srv_queue_size; /* number of sessions waiting for a connect slot on this server at accept() time (in direct assignment) */
644 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 +0100645 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100646 char *cli_cookie; /* cookie presented by the client, in capture mode */
647 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100648 int status; /* HTTP status from the server, negative if from proxy */
649 long long bytes; /* number of bytes transferred from the server */
650 } logs;
willy tarreau1f431b52006-05-21 14:46:15 +0200651 short int data_source; /* where to get the data we generate ourselves */
652 short int data_state; /* where to get the data we generate ourselves */
willy tarreaue0331262006-05-15 03:02:46 +0200653 union {
654 struct {
655 struct proxy *px;
656 struct server *sv;
willy tarreau1f431b52006-05-21 14:46:15 +0200657 short px_st, sv_st; /* DATA_ST_INIT or DATA_ST_DATA */
willy tarreaue0331262006-05-15 03:02:46 +0200658 } stats;
659 } data_ctx;
willy tarreau2f6ba652005-12-17 13:57:42 +0100660 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100661};
662
willy tarreaua41a8b42005-12-17 14:02:24 +0100663struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100664 int fd; /* the listen socket */
665 struct sockaddr_storage addr; /* the address we listen to */
666 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100667};
willy tarreauf32f5242006-05-02 22:54:52 +0200668
willy tarreau0f7af912005-12-17 12:21:26 +0100669struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100670 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100671 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 +0100672 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100673 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200674 struct server *srv; /* known servers */
675 int srv_act, srv_bck; /* # of running servers */
676 int tot_wact, tot_wbck; /* total weights of active and backup servers */
677 struct server **srv_map; /* the server map used to apply weights */
678 int srv_map_sz; /* the size of the effective server map */
679 int srv_rr_idx; /* next server to be elected in round robin mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100680 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100681 int cookie_len; /* strlen(cookie_name), computed only once */
682 char *appsession_name; /* name of the cookie to look for */
683 int appsession_name_len; /* strlen(appsession_name), computed only once */
684 int appsession_len; /* length of the appsession cookie value to be used */
685 int appsession_timeout;
686 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100687 char *capture_name; /* beginning of the name of the cookie to capture */
688 int capture_namelen; /* length of the cookie name to match */
689 int capture_len; /* length of the string to be captured */
willy tarreau9e138862006-05-14 23:06:28 +0200690 struct uri_auth *uri_auth; /* if non-NULL, the (list of) per-URI authentications */
willy tarreau0f7af912005-12-17 12:21:26 +0100691 int clitimeout; /* client I/O timeout (in milliseconds) */
692 int srvtimeout; /* server I/O timeout (in milliseconds) */
693 int contimeout; /* connect timeout (in milliseconds) */
694 char *id; /* proxy id */
willy tarreaudfece232006-05-02 00:19:57 +0200695 struct list pendconns; /* pending connections with no server assigned yet */
willy tarreaucb406512006-05-18 00:52:35 +0200696 int nbpend, nbpend_max; /* number of pending connections with no server assigned yet */
willy tarreauf32f5242006-05-02 22:54:52 +0200697 int totpend; /* total number of pending connections on this instance (for stats) */
willy tarreaucb406512006-05-18 00:52:35 +0200698 int nbconn, nbconn_max; /* # of active sessions */
willy tarreau14b4d432006-04-07 18:23:29 +0200699 unsigned int cum_conn; /* cumulated number of processed sessions */
willy tarreau0f7af912005-12-17 12:21:26 +0100700 int maxconn; /* max # of active sessions */
willy tarreaue3b30652006-05-21 16:23:22 +0200701 unsigned failed_conns, failed_resp; /* failed connect() and responses */
702 unsigned failed_secu; /* blocked responses because of security concerns */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100703 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100704 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100705 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100706 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100707 struct proxy *next;
708 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100709 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100710 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100711 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100712 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100713 int nb_reqadd, nb_rspadd;
714 struct hdr_exp *req_exp; /* regular expressions for request headers */
715 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100716 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
717 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
718 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
719 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100720 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100721 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100722 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
723 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100724 struct {
725 char *msg400; /* message for error 400 */
726 int len400; /* message length for error 400 */
727 char *msg403; /* message for error 403 */
728 int len403; /* message length for error 403 */
729 char *msg408; /* message for error 408 */
730 int len408; /* message length for error 408 */
731 char *msg500; /* message for error 500 */
732 int len500; /* message length for error 500 */
733 char *msg502; /* message for error 502 */
734 int len502; /* message length for error 502 */
735 char *msg503; /* message for error 503 */
736 int len503; /* message length for error 503 */
737 char *msg504; /* message for error 504 */
738 int len504; /* message length for error 504 */
739 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100740};
741
742/* info about one given fd */
743struct fdtab {
744 int (*read)(int fd); /* read function */
745 int (*write)(int fd); /* write function */
746 struct task *owner; /* the session (or proxy) associated with this fd */
747 int state; /* the state of this fd */
748};
749
750/*********************************************************************/
751
willy tarreaub952e1d2005-12-18 01:31:20 +0100752int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100753int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100754char *cfg_cfgfile = NULL; /* configuration file */
755char *progname = NULL; /* program name */
756int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100757
758/* global options */
759static struct {
760 int uid;
761 int gid;
762 int nbproc;
763 int maxconn;
764 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100765 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100766 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100767 int mode;
768 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100769 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100770 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100771 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100772 struct sockaddr_in logsrv1, logsrv2;
773} global = {
774 logfac1 : -1,
775 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100776 loglev1 : 7, /* max syslog level : debug */
777 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100778 /* others NULL OK */
779};
780
willy tarreau0f7af912005-12-17 12:21:26 +0100781/*********************************************************************/
782
willy tarreau1c2ad212005-12-18 01:11:29 +0100783fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100784 *StaticWriteEvent;
785
willy tarreau64a3cc32005-12-18 01:13:11 +0100786int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100787
willy tarreau0f7af912005-12-17 12:21:26 +0100788void **pool_session = NULL,
willy tarreau18a957c2006-04-12 19:26:23 +0200789 **pool_pendconn = NULL,
willy tarreau0f7af912005-12-17 12:21:26 +0100790 **pool_buffer = NULL,
791 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100792 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100793 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100794 **pool_capture = NULL,
795 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100796
797struct proxy *proxy = NULL; /* list of all existing proxies */
798struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100799struct task *rq = NULL; /* global run queue */
willy tarreau5e698ef2006-05-02 14:51:00 +0200800struct task wait_queue[2] = { /* global wait queue */
801 {
802 prev:LIST_HEAD(wait_queue[0]), /* expirable tasks */
803 next:LIST_HEAD(wait_queue[0]),
804 },
805 {
806 prev:LIST_HEAD(wait_queue[1]), /* non-expirable tasks */
807 next:LIST_HEAD(wait_queue[1]),
808 },
willy tarreau5cbea6f2005-12-17 12:48:26 +0100809};
willy tarreau0f7af912005-12-17 12:21:26 +0100810
willy tarreau0f7af912005-12-17 12:21:26 +0100811static int totalconn = 0; /* total # of terminated sessions */
812static int actconn = 0; /* # of active sessions */
813static int maxfd = 0; /* # of the highest fd + 1 */
814static int listeners = 0; /* # of listeners */
815static int stopping = 0; /* non zero means stopping in progress */
816static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaue0331262006-05-15 03:02:46 +0200817static struct timeval start_date; /* the process's start date */
willy tarreaua41a8b42005-12-17 14:02:24 +0100818static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100819
willy tarreau53e99702006-03-25 18:53:50 +0100820/* Here we store informations about the pids of the processes we may pause
821 * or kill. We will send them a signal every 10 ms until we can bind to all
822 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100823 */
willy tarreau53e99702006-03-25 18:53:50 +0100824#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100825static int nb_oldpids = 0;
826static int *oldpids = NULL;
827static int oldpids_sig; /* use USR1 or TERM */
828
willy tarreau08dedbe2005-12-18 01:13:48 +0100829#if defined(ENABLE_EPOLL)
830/* FIXME: this is dirty, but at the moment, there's no other solution to remove
831 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
832 * structure with pointers to functions such as init_fd() and close_fd(), plus
833 * a private structure with several pointers to places such as below.
834 */
835
836static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
837#endif
838
willy tarreau0f7af912005-12-17 12:21:26 +0100839static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100840/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100841static char trash[BUFSIZE];
842
willy tarreaudd07e972005-12-18 00:48:48 +0100843const int zero = 0;
844const int one = 1;
845
willy tarreau0f7af912005-12-17 12:21:26 +0100846/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100847 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100848 */
849
850#define MAX_SYSLOG_LEN 1024
851#define NB_LOG_FACILITIES 24
852const char *log_facilities[NB_LOG_FACILITIES] = {
853 "kern", "user", "mail", "daemon",
854 "auth", "syslog", "lpr", "news",
855 "uucp", "cron", "auth2", "ftp",
856 "ntp", "audit", "alert", "cron2",
857 "local0", "local1", "local2", "local3",
858 "local4", "local5", "local6", "local7"
859};
860
861
862#define NB_LOG_LEVELS 8
863const char *log_levels[NB_LOG_LEVELS] = {
864 "emerg", "alert", "crit", "err",
865 "warning", "notice", "info", "debug"
866};
867
868#define SYSLOG_PORT 514
869
870const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
871 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100872
willy tarreaub1285d52005-12-18 01:20:14 +0100873const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau078c79a2006-05-13 12:23:58 +0200874const char sess_fin_state[8] = "-RCHDLQ7"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, unknown */
willy tarreau036e1ce2005-12-17 13:46:33 +0100875const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
876const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
877 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
878 unknown, Set-cookie Rewritten */
879
willy tarreau0f7af912005-12-17 12:21:26 +0100880#define MAX_HOSTNAME_LEN 32
881static char hostname[MAX_HOSTNAME_LEN] = "";
882
willy tarreau8337c6b2005-12-17 13:41:01 +0100883const char *HTTP_302 =
884 "HTTP/1.0 302 Found\r\n"
885 "Cache-Control: no-cache\r\n"
886 "Connection: close\r\n"
887 "Location: "; /* not terminated since it will be concatenated with the URL */
888
willy tarreauc1f47532005-12-18 01:08:26 +0100889/* same as 302 except that the browser MUST retry with the GET method */
890const char *HTTP_303 =
891 "HTTP/1.0 303 See Other\r\n"
892 "Cache-Control: no-cache\r\n"
893 "Connection: close\r\n"
894 "Location: "; /* not terminated since it will be concatenated with the URL */
895
willy tarreaua1598082005-12-17 13:08:06 +0100896const char *HTTP_400 =
897 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100898 "Cache-Control: no-cache\r\n"
899 "Connection: close\r\n"
900 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100901 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100902
willy tarreau9e138862006-05-14 23:06:28 +0200903/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
904const char *HTTP_401_fmt =
905 "HTTP/1.0 401 Unauthorized\r\n"
906 "Cache-Control: no-cache\r\n"
907 "Connection: close\r\n"
908 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
909 "\r\n"
910 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
911
willy tarreaua1598082005-12-17 13:08:06 +0100912const char *HTTP_403 =
913 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100914 "Cache-Control: no-cache\r\n"
915 "Connection: close\r\n"
916 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100917 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
918
willy tarreau8337c6b2005-12-17 13:41:01 +0100919const char *HTTP_408 =
920 "HTTP/1.0 408 Request Time-out\r\n"
921 "Cache-Control: no-cache\r\n"
922 "Connection: close\r\n"
923 "\r\n"
924 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
925
willy tarreau750a4722005-12-17 13:21:24 +0100926const char *HTTP_500 =
927 "HTTP/1.0 500 Server Error\r\n"
928 "Cache-Control: no-cache\r\n"
929 "Connection: close\r\n"
930 "\r\n"
931 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100932
933const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100934 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100935 "Cache-Control: no-cache\r\n"
936 "Connection: close\r\n"
937 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100938 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
939
940const char *HTTP_503 =
941 "HTTP/1.0 503 Service Unavailable\r\n"
942 "Cache-Control: no-cache\r\n"
943 "Connection: close\r\n"
944 "\r\n"
945 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
946
947const char *HTTP_504 =
948 "HTTP/1.0 504 Gateway Time-out\r\n"
949 "Cache-Control: no-cache\r\n"
950 "Connection: close\r\n"
951 "\r\n"
952 "<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 +0100953
willy tarreau0f7af912005-12-17 12:21:26 +0100954/*********************************************************************/
955/* statistics ******************************************************/
956/*********************************************************************/
957
willy tarreau750a4722005-12-17 13:21:24 +0100958#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100959static int stats_tsk_lsrch, stats_tsk_rsrch,
960 stats_tsk_good, stats_tsk_right, stats_tsk_left,
961 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100962#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100963
964
965/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100966/* debugging *******************************************************/
967/*********************************************************************/
968#ifdef DEBUG_FULL
969static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau3504a012006-05-14 23:20:07 +0200970static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau750a4722005-12-17 13:21:24 +0100971#endif
972
973/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100974/* function prototypes *********************************************/
975/*********************************************************************/
976
977int event_accept(int fd);
978int event_cli_read(int fd);
979int event_cli_write(int fd);
980int event_srv_read(int fd);
981int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100982int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100983
willy tarreau12350152005-12-18 01:03:27 +0100984static int appsession_task_init(void);
985static int appsession_init(void);
986static int appsession_refresh(struct task *t);
987
willy tarreau0f7af912005-12-17 12:21:26 +0100988/*********************************************************************/
989/* general purpose functions ***************************************/
990/*********************************************************************/
991
992void display_version() {
993 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100994 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100995}
996
997/*
998 * This function prints the command line usage and exits
999 */
1000void usage(char *name) {
1001 display_version();
1002 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +01001003 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +01001004#if STATTIME > 0
1005 "sl"
1006#endif
willy tarreau746e26b2006-03-25 11:14:35 +01001007 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
1008 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +01001009 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +01001010 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +01001011 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +01001012#if STATTIME > 0
1013 " -s enables statistics output\n"
1014 " -l enables long statistics format\n"
1015#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001016 " -D goes daemon ; implies -q\n"
1017 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +01001018 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +01001019 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +01001020 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +01001021 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +01001022 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001023#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01001024 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001025#endif
1026#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01001027 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001028#endif
willy tarreau53e99702006-03-25 18:53:50 +01001029 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +01001030 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01001031 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +01001032 exit(1);
1033}
1034
1035
1036/*
willy tarreaud0fb4652005-12-18 01:32:04 +01001037 * Displays the message on stderr with the date and pid. Overrides the quiet
1038 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +01001039 */
1040void Alert(char *fmt, ...) {
1041 va_list argp;
1042 struct timeval tv;
1043 struct tm *tm;
1044
willy tarreaud0fb4652005-12-18 01:32:04 +01001045 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001046 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +01001047
willy tarreau5cbea6f2005-12-17 12:48:26 +01001048 gettimeofday(&tv, NULL);
1049 tm=localtime(&tv.tv_sec);
1050 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001051 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001052 vfprintf(stderr, fmt, argp);
1053 fflush(stderr);
1054 va_end(argp);
1055 }
willy tarreau0f7af912005-12-17 12:21:26 +01001056}
1057
1058
1059/*
1060 * Displays the message on stderr with the date and pid.
1061 */
1062void Warning(char *fmt, ...) {
1063 va_list argp;
1064 struct timeval tv;
1065 struct tm *tm;
1066
willy tarreau982249e2005-12-18 00:57:06 +01001067 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001068 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +01001069
willy tarreau5cbea6f2005-12-17 12:48:26 +01001070 gettimeofday(&tv, NULL);
1071 tm=localtime(&tv.tv_sec);
1072 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001073 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001074 vfprintf(stderr, fmt, argp);
1075 fflush(stderr);
1076 va_end(argp);
1077 }
1078}
1079
1080/*
1081 * Displays the message on <out> only if quiet mode is not set.
1082 */
1083void qfprintf(FILE *out, char *fmt, ...) {
1084 va_list argp;
1085
willy tarreau982249e2005-12-18 00:57:06 +01001086 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001087 va_start(argp, fmt);
1088 vfprintf(out, fmt, argp);
1089 fflush(out);
1090 va_end(argp);
1091 }
willy tarreau0f7af912005-12-17 12:21:26 +01001092}
1093
1094
1095/*
1096 * converts <str> to a struct sockaddr_in* which is locally allocated.
1097 * The format is "addr:port", where "addr" can be empty or "*" to indicate
1098 * INADDR_ANY.
1099 */
1100struct sockaddr_in *str2sa(char *str) {
1101 static struct sockaddr_in sa;
1102 char *c;
1103 int port;
1104
willy tarreaua1598082005-12-17 13:08:06 +01001105 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +01001106 str=strdup(str);
1107
1108 if ((c=strrchr(str,':')) != NULL) {
1109 *c++=0;
1110 port=atol(c);
1111 }
1112 else
1113 port=0;
1114
1115 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1116 sa.sin_addr.s_addr = INADDR_ANY;
1117 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01001118 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001119 struct hostent *he;
1120
1121 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001122 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001123 }
1124 else
1125 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1126 }
1127 sa.sin_port=htons(port);
1128 sa.sin_family=AF_INET;
1129
1130 free(str);
1131 return &sa;
1132}
1133
willy tarreaub1285d52005-12-18 01:20:14 +01001134/*
1135 * converts <str> to a two struct in_addr* which are locally allocated.
1136 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1137 * is optionnal and either in the dotted or CIDR notation.
1138 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1139 */
1140int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1141 char *c;
1142 unsigned long len;
1143
1144 memset(mask, 0, sizeof(*mask));
1145 memset(addr, 0, sizeof(*addr));
1146 str=strdup(str);
1147
1148 if ((c = strrchr(str, '/')) != NULL) {
1149 *c++ = 0;
1150 /* c points to the mask */
1151 if (strchr(c, '.') != NULL) { /* dotted notation */
1152 if (!inet_pton(AF_INET, c, mask))
1153 return 0;
1154 }
1155 else { /* mask length */
1156 char *err;
1157 len = strtol(c, &err, 10);
1158 if (!*c || (err && *err) || (unsigned)len > 32)
1159 return 0;
1160 if (len)
1161 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1162 else
1163 mask->s_addr = 0;
1164 }
1165 }
1166 else {
1167 mask->s_addr = 0xFFFFFFFF;
1168 }
1169 if (!inet_pton(AF_INET, str, addr)) {
1170 struct hostent *he;
1171
1172 if ((he = gethostbyname(str)) == NULL) {
1173 return 0;
1174 }
1175 else
1176 *addr = *(struct in_addr *) *(he->h_addr_list);
1177 }
1178 free(str);
1179 return 1;
1180}
1181
willy tarreau9fe663a2005-12-17 13:02:59 +01001182
1183/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001184 * converts <str> to a list of listeners which are dynamically allocated.
1185 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1186 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1187 * - <port> is a numerical port from 1 to 65535 ;
1188 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1189 * This can be repeated as many times as necessary, separated by a coma.
1190 * The <tail> argument is a pointer to a current list which should be appended
1191 * to the tail of the new list. The pointer to the new list is returned.
1192 */
1193struct listener *str2listener(char *str, struct listener *tail) {
1194 struct listener *l;
1195 char *c, *next, *range, *dupstr;
1196 int port, end;
1197
1198 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001199
willy tarreaua41a8b42005-12-17 14:02:24 +01001200 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001201 struct sockaddr_storage ss;
1202
willy tarreaua41a8b42005-12-17 14:02:24 +01001203 str = next;
1204 /* 1) look for the end of the first address */
1205 if ((next = strrchr(str, ',')) != NULL) {
1206 *next++ = 0;
1207 }
1208
willy tarreau8a86dbf2005-12-18 00:45:59 +01001209 /* 2) look for the addr/port delimiter, it's the last colon. */
1210 if ((range = strrchr(str, ':')) == NULL) {
1211 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001212 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001213 }
1214
1215 *range++ = 0;
1216
1217 if (strrchr(str, ':') != NULL) {
1218 /* IPv6 address contains ':' */
1219 memset(&ss, 0, sizeof(ss));
1220 ss.ss_family = AF_INET6;
1221
1222 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1223 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001224 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001225 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001226 }
1227 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001228 memset(&ss, 0, sizeof(ss));
1229 ss.ss_family = AF_INET;
1230
1231 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1232 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1233 }
1234 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1235 struct hostent *he;
1236
1237 if ((he = gethostbyname(str)) == NULL) {
1238 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001239 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001240 }
1241 else
1242 ((struct sockaddr_in *)&ss)->sin_addr =
1243 *(struct in_addr *) *(he->h_addr_list);
1244 }
1245 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001246
1247 /* 3) look for the port-end delimiter */
1248 if ((c = strchr(range, '-')) != NULL) {
1249 *c++ = 0;
1250 end = atol(c);
1251 }
1252 else {
1253 end = atol(range);
1254 }
1255
willy tarreaud0fb4652005-12-18 01:32:04 +01001256 port = atol(range);
1257
1258 if (port < 1 || port > 65535) {
1259 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1260 goto fail;
1261 }
1262
1263 if (end < 1 || end > 65535) {
1264 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1265 goto fail;
1266 }
1267
1268 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001269 l = (struct listener *)calloc(1, sizeof(struct listener));
1270 l->next = tail;
1271 tail = l;
1272
willy tarreau41310e72006-03-25 18:17:56 +01001273 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001274 l->addr = ss;
1275 if (ss.ss_family == AF_INET6)
1276 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1277 else
1278 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1279
willy tarreaua41a8b42005-12-17 14:02:24 +01001280 } /* end for(port) */
1281 } /* end while(next) */
1282 free(dupstr);
1283 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001284 fail:
1285 free(dupstr);
1286 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001287}
1288
willy tarreau4302f492005-12-18 01:00:37 +01001289
1290#define FD_SETS_ARE_BITFIELDS
1291#ifdef FD_SETS_ARE_BITFIELDS
1292/*
1293 * This map is used with all the FD_* macros to check whether a particular bit
1294 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1295 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1296 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1297 * exclusively to the macros.
1298 */
1299fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1300fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1301
1302#else
1303#error "Check if your OS uses bitfields for fd_sets"
1304#endif
1305
1306/* will try to encode the string <string> replacing all characters tagged in
1307 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1308 * prefixed by <escape>, and will store the result between <start> (included
1309 *) and <stop> (excluded), and will always terminate the string with a '\0'
1310 * before <stop>. The position of the '\0' is returned if the conversion
1311 * completes. If bytes are missing between <start> and <stop>, then the
1312 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1313 * cannot even be stored so we return <start> without writing the 0.
1314 * The input string must also be zero-terminated.
1315 */
1316char hextab[16] = "0123456789ABCDEF";
1317char *encode_string(char *start, char *stop,
1318 const char escape, const fd_set *map,
1319 const char *string)
1320{
1321 if (start < stop) {
1322 stop--; /* reserve one byte for the final '\0' */
1323 while (start < stop && *string != 0) {
1324 if (!FD_ISSET((unsigned char)(*string), map))
1325 *start++ = *string;
1326 else {
1327 if (start + 3 >= stop)
1328 break;
1329 *start++ = escape;
1330 *start++ = hextab[(*string >> 4) & 15];
1331 *start++ = hextab[*string & 15];
1332 }
1333 string++;
1334 }
1335 *start = '\0';
1336 }
1337 return start;
1338}
willy tarreaua41a8b42005-12-17 14:02:24 +01001339
1340/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001341 * This function sends a syslog message to both log servers of a proxy,
1342 * or to global log servers if the proxy is NULL.
1343 * It also tries not to waste too much time computing the message header.
1344 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001345 */
1346void send_log(struct proxy *p, int level, char *message, ...) {
1347 static int logfd = -1; /* syslog UDP socket */
1348 static long tvsec = -1; /* to force the string to be initialized */
1349 struct timeval tv;
1350 va_list argp;
1351 static char logmsg[MAX_SYSLOG_LEN];
1352 static char *dataptr = NULL;
1353 int fac_level;
1354 int hdr_len, data_len;
1355 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001356 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001357 int nbloggers = 0;
1358 char *log_ptr;
1359
1360 if (logfd < 0) {
1361 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1362 return;
1363 }
1364
1365 if (level < 0 || progname == NULL || message == NULL)
1366 return;
1367
1368 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001369 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001370 /* this string is rebuild only once a second */
1371 struct tm *tm = localtime(&tv.tv_sec);
1372 tvsec = tv.tv_sec;
1373
willy tarreauc29948c2005-12-17 13:10:27 +01001374 hdr_len = snprintf(logmsg, sizeof(logmsg),
1375 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1376 monthname[tm->tm_mon],
1377 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1378 progname, pid);
1379 /* WARNING: depending upon implementations, snprintf may return
1380 * either -1 or the number of bytes that would be needed to store
1381 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001382 */
willy tarreauc29948c2005-12-17 13:10:27 +01001383 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1384 hdr_len = sizeof(logmsg);
1385
1386 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001387 }
1388
1389 va_start(argp, message);
1390 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001391 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1392 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001393 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001394 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001395
1396 if (p == NULL) {
1397 if (global.logfac1 >= 0) {
1398 sa[nbloggers] = &global.logsrv1;
1399 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001400 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001401 nbloggers++;
1402 }
1403 if (global.logfac2 >= 0) {
1404 sa[nbloggers] = &global.logsrv2;
1405 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001406 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001407 nbloggers++;
1408 }
1409 } else {
1410 if (p->logfac1 >= 0) {
1411 sa[nbloggers] = &p->logsrv1;
1412 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001413 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001414 nbloggers++;
1415 }
1416 if (p->logfac2 >= 0) {
1417 sa[nbloggers] = &p->logsrv2;
1418 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001419 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001420 nbloggers++;
1421 }
1422 }
1423
1424 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001425 /* we can filter the level of the messages that are sent to each logger */
1426 if (level > loglevel[nbloggers])
1427 continue;
1428
willy tarreauc29948c2005-12-17 13:10:27 +01001429 /* For each target, we may have a different facility.
1430 * We can also have a different log level for each message.
1431 * This induces variations in the message header length.
1432 * Since we don't want to recompute it each time, nor copy it every
1433 * time, we only change the facility in the pre-computed header,
1434 * and we change the pointer to the header accordingly.
1435 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001436 fac_level = (facilities[nbloggers] << 3) + level;
1437 log_ptr = logmsg + 3; /* last digit of the log level */
1438 do {
1439 *log_ptr = '0' + fac_level % 10;
1440 fac_level /= 10;
1441 log_ptr--;
1442 } while (fac_level && log_ptr > logmsg);
1443 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001444
willy tarreauc29948c2005-12-17 13:10:27 +01001445 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001446
1447#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001448 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001449 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1450#else
willy tarreauc29948c2005-12-17 13:10:27 +01001451 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001452 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1453#endif
1454 }
willy tarreau0f7af912005-12-17 12:21:26 +01001455}
1456
1457
1458/* sets <tv> to the current time */
1459static inline struct timeval *tv_now(struct timeval *tv) {
1460 if (tv)
1461 gettimeofday(tv, NULL);
1462 return tv;
1463}
1464
1465/*
1466 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1467 */
willy tarreaudab722b2006-05-04 19:23:38 +02001468static struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
willy tarreau0f7af912005-12-17 12:21:26 +01001469 if (!tv || !from)
1470 return NULL;
1471 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1472 tv->tv_sec = from->tv_sec + (ms/1000);
1473 while (tv->tv_usec >= 1000000) {
1474 tv->tv_usec -= 1000000;
1475 tv->tv_sec++;
1476 }
1477 return tv;
1478}
1479
1480/*
1481 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001482 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001483 */
1484static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001485 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001486 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001487 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001488 return 1;
1489 else if (tv1->tv_usec < tv2->tv_usec)
1490 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001491 else if (tv1->tv_usec > tv2->tv_usec)
1492 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001493 else
1494 return 0;
1495}
1496
1497/*
1498 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001499 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001500 */
1501unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1502 int cmp;
1503 unsigned long ret;
1504
1505
willy tarreauef900ab2005-12-17 12:52:52 +01001506 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001507 if (!cmp)
1508 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001509 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001510 struct timeval *tmp = tv1;
1511 tv1 = tv2;
1512 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001513 }
willy tarreauef900ab2005-12-17 12:52:52 +01001514 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001515 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001516 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001517 else
willy tarreauef900ab2005-12-17 12:52:52 +01001518 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001519 return (unsigned long) ret;
1520}
1521
1522/*
willy tarreau750a4722005-12-17 13:21:24 +01001523 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001524 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001525 */
1526static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1527 unsigned long ret;
1528
willy tarreau6e682ce2005-12-17 13:26:49 +01001529 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1530 if (tv2->tv_usec > tv1->tv_usec)
1531 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001532 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001533 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001534 return (unsigned long) ret;
1535}
1536
1537/*
willy tarreau0f7af912005-12-17 12:21:26 +01001538 * 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 +01001539 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001540 */
willy tarreaudab722b2006-05-04 19:23:38 +02001541static int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001542 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001543 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001544 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001545 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001546 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001547 else
1548 return 0;
1549 }
willy tarreau0f7af912005-12-17 12:21:26 +01001550 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001551 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001552 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001553 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001554 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001555 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001556 else
1557 return 0;
1558}
1559
1560/*
1561 * returns the remaining time between tv1=now and event=tv2
1562 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001563 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001564 */
1565static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1566 unsigned long ret;
1567
willy tarreau0f7af912005-12-17 12:21:26 +01001568 if (tv_cmp_ms(tv1, tv2) >= 0)
1569 return 0; /* event elapsed */
1570
willy tarreauef900ab2005-12-17 12:52:52 +01001571 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001572 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001573 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001574 else
willy tarreauef900ab2005-12-17 12:52:52 +01001575 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001576 return (unsigned long) ret;
1577}
1578
1579
1580/*
1581 * zeroes a struct timeval
1582 */
1583
1584static inline struct timeval *tv_eternity(struct timeval *tv) {
1585 tv->tv_sec = tv->tv_usec = 0;
1586 return tv;
1587}
1588
1589/*
1590 * returns 1 if tv is null, else 0
1591 */
1592static inline int tv_iseternity(struct timeval *tv) {
1593 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1594 return 1;
1595 else
1596 return 0;
1597}
1598
1599/*
1600 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1601 * considering that 0 is the eternity.
1602 */
willy tarreaudab722b2006-05-04 19:23:38 +02001603static int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001604 if (tv_iseternity(tv1))
1605 if (tv_iseternity(tv2))
1606 return 0; /* same */
1607 else
1608 return 1; /* tv1 later than tv2 */
1609 else if (tv_iseternity(tv2))
1610 return -1; /* tv2 later than tv1 */
1611
1612 if (tv1->tv_sec > tv2->tv_sec)
1613 return 1;
1614 else if (tv1->tv_sec < tv2->tv_sec)
1615 return -1;
1616 else if (tv1->tv_usec > tv2->tv_usec)
1617 return 1;
1618 else if (tv1->tv_usec < tv2->tv_usec)
1619 return -1;
1620 else
1621 return 0;
1622}
1623
1624/*
1625 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1626 * considering that 0 is the eternity.
1627 */
willy tarreaudab722b2006-05-04 19:23:38 +02001628static int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001629 if (tv_iseternity(tv1))
1630 if (tv_iseternity(tv2))
1631 return 0; /* same */
1632 else
1633 return 1; /* tv1 later than tv2 */
1634 else if (tv_iseternity(tv2))
1635 return -1; /* tv2 later than tv1 */
1636
willy tarreauefae1842005-12-17 12:51:03 +01001637 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001638 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001639 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001640 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001641 return -1;
1642 else
1643 return 0;
1644 }
1645 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001646 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001647 return 1;
1648 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001649 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001650 return -1;
1651 else
1652 return 0;
1653}
1654
1655/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001656 * returns the remaining time between tv1=now and event=tv2
1657 * if tv2 is passed, 0 is returned.
1658 * Returns TIME_ETERNITY if tv2 is eternity.
1659 */
willy tarreaudab722b2006-05-04 19:23:38 +02001660static unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001661 unsigned long ret;
1662
1663 if (tv_iseternity(tv2))
1664 return TIME_ETERNITY;
1665
1666 if (tv_cmp_ms(tv1, tv2) >= 0)
1667 return 0; /* event elapsed */
1668
1669 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1670 if (tv2->tv_usec > tv1->tv_usec)
1671 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1672 else
1673 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1674 return (unsigned long) ret;
1675}
1676
1677/*
willy tarreau0f7af912005-12-17 12:21:26 +01001678 * returns the first event between tv1 and tv2 into tvmin.
1679 * a zero tv is ignored. tvmin is returned.
1680 */
1681static inline struct timeval *tv_min(struct timeval *tvmin,
1682 struct timeval *tv1, struct timeval *tv2) {
1683
1684 if (tv_cmp2(tv1, tv2) <= 0)
1685 *tvmin = *tv1;
1686 else
1687 *tvmin = *tv2;
1688
1689 return tvmin;
1690}
1691
1692
1693
1694/***********************************************************/
1695/* fd management ***************************************/
1696/***********************************************************/
1697
1698
1699
willy tarreau5cbea6f2005-12-17 12:48:26 +01001700/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1701 * The file descriptor is also closed.
1702 */
willy tarreaudab722b2006-05-04 19:23:38 +02001703static void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001704 FD_CLR(fd, StaticReadEvent);
1705 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001706#if defined(ENABLE_EPOLL)
1707 if (PrevReadEvent) {
1708 FD_CLR(fd, PrevReadEvent);
1709 FD_CLR(fd, PrevWriteEvent);
1710 }
1711#endif
1712
willy tarreau5cbea6f2005-12-17 12:48:26 +01001713 close(fd);
1714 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001715
1716 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1717 maxfd--;
1718}
1719
1720/* recomputes the maxfd limit from the fd */
1721static inline void fd_insert(int fd) {
1722 if (fd+1 > maxfd)
1723 maxfd = fd+1;
1724}
1725
1726/*************************************************************/
1727/* task management ***************************************/
1728/*************************************************************/
1729
willy tarreau5cbea6f2005-12-17 12:48:26 +01001730/* puts the task <t> in run queue <q>, and returns <t> */
1731static inline struct task *task_wakeup(struct task **q, struct task *t) {
1732 if (t->state == TASK_RUNNING)
1733 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001734 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001735 t->rqnext = *q;
1736 t->state = TASK_RUNNING;
1737 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001738 }
1739}
1740
willy tarreau5cbea6f2005-12-17 12:48:26 +01001741/* removes the task <t> from the queue <q>
1742 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001743 * set the run queue to point to the next one, and return it
1744 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001745static inline struct task *task_sleep(struct task **q, struct task *t) {
1746 if (t->state == TASK_RUNNING) {
1747 *q = t->rqnext;
1748 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001749 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001750 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001751}
1752
1753/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001754 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001755 * from the run queue. A pointer to the task itself is returned.
1756 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001757static inline struct task *task_delete(struct task *t) {
1758 t->prev->next = t->next;
1759 t->next->prev = t->prev;
1760 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001761}
1762
1763/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001764 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001765 */
1766static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001767 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001768}
1769
willy tarreau5cbea6f2005-12-17 12:48:26 +01001770/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001771 * may be only moved or left where it was, depending on its timing requirements.
1772 * <task> is returned.
1773 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001774struct task *task_queue(struct task *task) {
1775 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001776 struct task *start_from;
1777
willy tarreau5e698ef2006-05-02 14:51:00 +02001778 /* This is a very dirty hack to queue non-expirable tasks in another queue
1779 * in order to avoid pulluting the tail of the standard queue. This will go
1780 * away with the new O(log(n)) scheduler anyway.
1781 */
1782 if (tv_iseternity(&task->expire)) {
1783 /* if the task was queued in the standard wait queue, we must dequeue it */
1784 if (task->prev) {
1785 if (task->wq == LIST_HEAD(wait_queue[1]))
1786 return task;
1787 else {
1788 task_delete(task);
1789 task->prev = NULL;
1790 }
1791 }
1792 list = task->wq = LIST_HEAD(wait_queue[1]);
1793 } else {
1794 /* if the task was queued in the eternity queue, we must dequeue it */
1795 if (task->prev && (task->wq == LIST_HEAD(wait_queue[1]))) {
1796 task_delete(task);
1797 task->prev = NULL;
1798 list = task->wq = LIST_HEAD(wait_queue[0]);
1799 }
1800 }
1801
1802 /* next, test if the task was already in a list */
willy tarreau0f7af912005-12-17 12:21:26 +01001803 if (task->prev == NULL) {
1804 // start_from = list;
1805 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001806#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001807 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001808#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001809 /* insert the unlinked <task> into the list, searching back from the last entry */
1810 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1811 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001812#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001813 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001814#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001815 }
1816
1817 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1818 // start_from = start_from->next;
1819 // stats_tsk_nsrch++;
1820 // }
1821 }
1822 else if (task->prev == list ||
1823 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1824 start_from = task->next;
1825 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001826#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001827 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001828#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001829 return task; /* it's already in the right place */
1830 }
1831
willy tarreau750a4722005-12-17 13:21:24 +01001832#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001833 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001834#endif
1835
1836 /* if the task is not at the right place, there's little chance that
1837 * it has only shifted a bit, and it will nearly always be queued
1838 * at the end of the list because of constant timeouts
1839 * (observed in real case).
1840 */
1841#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1842 start_from = list->prev; /* assume we'll queue to the end of the list */
1843 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1844 start_from = start_from->prev;
1845#if STATTIME > 0
1846 stats_tsk_lsrch++;
1847#endif
1848 }
1849#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001850 /* insert the unlinked <task> into the list, searching after position <start_from> */
1851 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1852 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001853#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001854 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001855#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001856 }
willy tarreau750a4722005-12-17 13:21:24 +01001857#endif /* WE_REALLY_... */
1858
willy tarreau0f7af912005-12-17 12:21:26 +01001859 /* we need to unlink it now */
1860 task_delete(task);
1861 }
1862 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001863#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001864 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001865#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001866#ifdef LEFT_TO_TOP /* not very good */
1867 start_from = list;
1868 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1869 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001870#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001871 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001872#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001873 }
1874#else
1875 start_from = task->prev->prev; /* valid because of the previous test above */
1876 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1877 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001878#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001879 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001880#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001881 }
1882#endif
1883 /* we need to unlink it now */
1884 task_delete(task);
1885 }
1886 task->prev = start_from;
1887 task->next = start_from->next;
1888 task->next->prev = task;
1889 start_from->next = task;
1890 return task;
1891}
1892
1893
1894/*********************************************************************/
willy tarreau18a957c2006-04-12 19:26:23 +02001895/* pending connections queues **************************************/
1896/*********************************************************************/
1897
1898/*
willy tarreaudfece232006-05-02 00:19:57 +02001899 * Detaches pending connection <p>, decreases the pending count, and frees
1900 * the pending connection. The connection might have been queued to a specific
1901 * server as well as to the proxy. The session also gets marked unqueued.
willy tarreau18a957c2006-04-12 19:26:23 +02001902 */
willy tarreaudfece232006-05-02 00:19:57 +02001903static void pendconn_free(struct pendconn *p) {
1904 LIST_DEL(&p->list);
1905 p->sess->pend_pos = NULL;
1906 if (p->srv)
1907 p->srv->nbpend--;
1908 else
1909 p->sess->proxy->nbpend--;
willy tarreauf32f5242006-05-02 22:54:52 +02001910 p->sess->proxy->totpend--;
willy tarreaudfece232006-05-02 00:19:57 +02001911 pool_free(pendconn, p);
1912}
1913
1914/* Returns the first pending connection for server <s>, which may be NULL if
1915 * nothing is pending.
1916 */
1917static inline struct pendconn *pendconn_from_srv(struct server *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001918 if (!s->nbpend)
1919 return NULL;
1920
1921 return LIST_ELEM(s->pendconns.n, struct pendconn *, list);
1922}
1923
willy tarreaudfece232006-05-02 00:19:57 +02001924/* Returns the first pending connection for proxy <px>, which may be NULL if
1925 * nothing is pending.
willy tarreau18a957c2006-04-12 19:26:23 +02001926 */
willy tarreaudfece232006-05-02 00:19:57 +02001927static inline struct pendconn *pendconn_from_px(struct proxy *px) {
1928 if (!px->nbpend)
1929 return NULL;
1930
1931 return LIST_ELEM(px->pendconns.n, struct pendconn *, list);
willy tarreau18a957c2006-04-12 19:26:23 +02001932}
1933
willy tarreaubc2eda62006-05-04 15:16:23 +02001934/* Detaches the next pending connection from either a server or a proxy, and
1935 * returns its associated session. If no pending connection is found, NULL is
1936 * returned. Note that neither <srv> nor <px> can be NULL.
willy tarreau18a957c2006-04-12 19:26:23 +02001937 */
willy tarreaubc2eda62006-05-04 15:16:23 +02001938static struct session *pendconn_get_next_sess(struct server *srv, struct proxy *px) {
willy tarreau18a957c2006-04-12 19:26:23 +02001939 struct pendconn *p;
1940 struct session *sess;
1941
willy tarreaubc2eda62006-05-04 15:16:23 +02001942 p = pendconn_from_srv(srv);
willy tarreaudfece232006-05-02 00:19:57 +02001943 if (!p) {
willy tarreaubc2eda62006-05-04 15:16:23 +02001944 p = pendconn_from_px(px);
willy tarreaudfece232006-05-02 00:19:57 +02001945 if (!p)
1946 return NULL;
willy tarreaubc2eda62006-05-04 15:16:23 +02001947 p->sess->srv = srv;
willy tarreaudfece232006-05-02 00:19:57 +02001948 }
willy tarreau18a957c2006-04-12 19:26:23 +02001949 sess = p->sess;
1950 pendconn_free(p);
1951 return sess;
1952}
1953
willy tarreaudfece232006-05-02 00:19:57 +02001954/* Adds the session <sess> to the pending connection list of server <sess>->srv
1955 * or to the one of <sess>->proxy if srv is NULL. All counters and back pointers
1956 * are updated accordingly. Returns NULL if no memory is available, otherwise the
1957 * pendconn itself.
willy tarreau18a957c2006-04-12 19:26:23 +02001958 */
willy tarreaudfece232006-05-02 00:19:57 +02001959static struct pendconn *pendconn_add(struct session *sess) {
willy tarreau18a957c2006-04-12 19:26:23 +02001960 struct pendconn *p;
1961
1962 p = pool_alloc(pendconn);
1963 if (!p)
1964 return NULL;
1965
willy tarreau18a957c2006-04-12 19:26:23 +02001966 sess->pend_pos = p;
willy tarreaudfece232006-05-02 00:19:57 +02001967 p->sess = sess;
1968 p->srv = sess->srv;
1969 if (sess->srv) {
1970 LIST_ADDQ(&sess->srv->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001971 sess->logs.srv_queue_size += sess->srv->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001972 sess->srv->nbpend++;
willy tarreaucb406512006-05-18 00:52:35 +02001973 if (sess->srv->nbpend > sess->srv->nbpend_max)
1974 sess->srv->nbpend_max = sess->srv->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001975 } else {
1976 LIST_ADDQ(&sess->proxy->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001977 sess->logs.prx_queue_size += sess->proxy->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001978 sess->proxy->nbpend++;
willy tarreaucb406512006-05-18 00:52:35 +02001979 if (sess->proxy->nbpend > sess->proxy->nbpend_max)
1980 sess->proxy->nbpend_max = sess->proxy->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001981 }
willy tarreauf32f5242006-05-02 22:54:52 +02001982 sess->proxy->totpend++;
willy tarreau18a957c2006-04-12 19:26:23 +02001983 return p;
1984}
1985
willy tarreau59a6cc22006-05-12 01:29:08 +02001986/* returns 0 if nothing has to be done for server <s> regarding queued connections,
1987 * and non-zero otherwise. Suited for and if/else usage.
1988 */
1989static inline int may_dequeue_tasks(struct server *s, struct proxy *p) {
1990 return (s && (s->nbpend || p->nbpend) &&
1991 s->maxconn && s->cur_sess < s->maxconn && s->queue_mgt);
1992}
1993
1994
1995
willy tarreau18a957c2006-04-12 19:26:23 +02001996/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +01001997/* more specific functions ***************************************/
1998/*********************************************************************/
1999
2000/* some prototypes */
2001static int maintain_proxies(void);
2002
willy tarreaub952e1d2005-12-18 01:31:20 +01002003/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01002004 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
2005 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01002006static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01002007#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002008 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
2009#else
willy tarreaua1598082005-12-17 13:08:06 +01002010#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002011 return getsockname(fd, (struct sockaddr *)sa, salen);
2012#else
2013 return -1;
2014#endif
2015#endif
2016}
2017
2018/*
2019 * frees the context associated to a session. It must have been removed first.
2020 */
willy tarreaudfece232006-05-02 00:19:57 +02002021static void session_free(struct session *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02002022 if (s->pend_pos)
2023 pendconn_free(s->pend_pos);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002024 if (s->req)
2025 pool_free(buffer, s->req);
2026 if (s->rep)
2027 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01002028
2029 if (s->rsp_cap != NULL) {
2030 struct cap_hdr *h;
2031 for (h = s->proxy->rsp_cap; h; h = h->next) {
2032 if (s->rsp_cap[h->index] != NULL)
2033 pool_free_to(h->pool, s->rsp_cap[h->index]);
2034 }
2035 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
2036 }
2037 if (s->req_cap != NULL) {
2038 struct cap_hdr *h;
2039 for (h = s->proxy->req_cap; h; h = h->next) {
2040 if (s->req_cap[h->index] != NULL)
2041 pool_free_to(h->pool, s->req_cap[h->index]);
2042 }
2043 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
2044 }
2045
willy tarreaua1598082005-12-17 13:08:06 +01002046 if (s->logs.uri)
2047 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01002048 if (s->logs.cli_cookie)
2049 pool_free(capture, s->logs.cli_cookie);
2050 if (s->logs.srv_cookie)
2051 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01002052
willy tarreau5cbea6f2005-12-17 12:48:26 +01002053 pool_free(session, s);
2054}
2055
willy tarreau0f7af912005-12-17 12:21:26 +01002056
2057/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01002058 * This function recounts the number of usable active and backup servers for
2059 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002060 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01002061 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002062static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002063 struct server *srv;
2064
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002065 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002066 for (srv = px->srv; srv != NULL; srv = srv->next) {
2067 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002068 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002069 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002070 px->tot_wbck += srv->eweight + 1;
2071 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002072 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002073 px->tot_wact += srv->eweight + 1;
2074 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01002075 }
2076 }
2077}
2078
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002079/* This function recomputes the server map for proxy px. It
2080 * relies on px->tot_wact and px->tot_wbck, so it must be
2081 * called after recount_servers(). It also expects px->srv_map
2082 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01002083 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002084static void recalc_server_map(struct proxy *px) {
2085 int o, tot, flag;
2086 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01002087
willy tarreau4c8c2b52006-03-24 19:36:41 +01002088 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002089 flag = SRV_RUNNING;
2090 tot = px->tot_wact;
2091 } else if (px->srv_bck) {
2092 flag = SRV_RUNNING | SRV_BACKUP;
2093 if (px->options & PR_O_USE_ALL_BK)
2094 tot = px->tot_wbck;
2095 else
2096 tot = 1; /* the first server is enough */
2097 } else {
2098 px->srv_map_sz = 0;
2099 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002100 }
Willy TARREAU3481c462006-03-01 22:37:57 +01002101
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002102 /* this algorithm gives priority to the first server, which means that
2103 * it will respect the declaration order for equivalent weights, and
2104 * that whatever the weights, the first server called will always be
2105 * the first declard. This is an important asumption for the backup
2106 * case, where we want the first server only.
2107 */
2108 for (cur = px->srv; cur; cur = cur->next)
2109 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002110
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002111 for (o = 0; o < tot; o++) {
2112 int max = 0;
2113 best = NULL;
2114 for (cur = px->srv; cur; cur = cur->next) {
2115 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
2116 int v;
2117
2118 /* If we are forced to return only one server, we don't want to
2119 * go further, because we would return the wrong one due to
2120 * divide overflow.
2121 */
2122 if (tot == 1) {
2123 best = cur;
2124 break;
2125 }
2126
2127 cur->wscore += cur->eweight + 1;
2128 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
2129 if (best == NULL || v > max) {
2130 max = v;
2131 best = cur;
2132 }
2133 }
2134 }
2135 px->srv_map[o] = best;
2136 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002137 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002138 px->srv_map_sz = tot;
2139}
Willy TARREAU3481c462006-03-01 22:37:57 +01002140
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002141/*
willy tarreau898db9d2006-04-12 20:29:08 +02002142 * This function tries to find a running server with free connection slots for
2143 * the proxy <px> following the round-robin method.
2144 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2145 * to point to the next server. If no valid server is found, NULL is returned.
2146 */
2147static inline struct server *get_server_rr_with_conns(struct proxy *px) {
2148 int newidx;
2149 struct server *srv;
2150
2151 if (px->srv_map_sz == 0)
2152 return NULL;
2153
2154 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2155 px->srv_rr_idx = 0;
2156 newidx = px->srv_rr_idx;
2157
2158 do {
2159 srv = px->srv_map[newidx++];
2160 if (!srv->maxconn || srv->cur_sess < srv->maxconn) {
2161 px->srv_rr_idx = newidx;
2162 return srv;
2163 }
2164 if (newidx == px->srv_map_sz)
2165 newidx = 0;
2166 } while (newidx != px->srv_rr_idx);
2167
2168 return NULL;
2169}
2170
2171
2172/*
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002173 * This function tries to find a running server for the proxy <px> following
willy tarreau898db9d2006-04-12 20:29:08 +02002174 * the round-robin method.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002175 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2176 * to point to the next server. If no valid server is found, NULL is returned.
2177 */
2178static inline struct server *get_server_rr(struct proxy *px) {
2179 if (px->srv_map_sz == 0)
2180 return NULL;
2181
2182 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2183 px->srv_rr_idx = 0;
2184 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01002185}
2186
willy tarreau62084d42006-03-24 18:57:41 +01002187
2188/*
willy tarreau1a3442d2006-03-24 21:03:20 +01002189 * This function tries to find a running server for the proxy <px> following
2190 * the source hash method. Depending on the number of active/backup servers,
2191 * it will either look for active servers, or for backup servers.
2192 * If any server is found, it will be returned. If no valid server is found,
2193 * NULL is returned.
2194 */
2195static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002196 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01002197
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002198 if (px->srv_map_sz == 0)
2199 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01002200
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002201 l = h = 0;
willy tarreaucd655352006-04-29 12:11:46 +02002202 if (px->srv_act > 1 || (px->srv_act == 0 && px->srv_bck > 1)) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002203 while ((l + sizeof (int)) <= len) {
2204 h ^= ntohl(*(unsigned int *)(&addr[l]));
2205 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01002206 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002207 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01002208 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002209 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01002210}
2211
2212
2213/*
willy tarreaudfece232006-05-02 00:19:57 +02002214 * This function marks the session as 'assigned' in direct or dispatch modes,
2215 * or tries to assign one in balance mode, according to the algorithm. It does
2216 * nothing if the session had already been assigned a server.
2217 *
2218 * It may return :
willy tarreau000375f2006-05-09 23:15:58 +02002219 * SRV_STATUS_OK if everything is OK. s->srv will be valid.
2220 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
2221 * SRV_STATUS_FULL if all servers are saturated. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002222 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2223 *
2224 * Upon successful return, the session flag SN_ASSIGNED to indicate that it does
2225 * not need to be called anymore. This usually means that s->srv can be trusted
2226 * in balance and direct modes. This flag is not cleared, so it's to the caller
2227 * to clear it if required (eg: redispatch).
2228 *
willy tarreau0f7af912005-12-17 12:21:26 +01002229 */
willy tarreau0f7af912005-12-17 12:21:26 +01002230
willy tarreaudfece232006-05-02 00:19:57 +02002231int assign_server(struct session *s) {
willy tarreau12350152005-12-18 01:03:27 +01002232#ifdef DEBUG_FULL
willy tarreaudfece232006-05-02 00:19:57 +02002233 fprintf(stderr,"assign_server : s=%p\n",s);
willy tarreau12350152005-12-18 01:03:27 +01002234#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002235
willy tarreaudfece232006-05-02 00:19:57 +02002236 if (s->pend_pos)
2237 return SRV_STATUS_INTERNAL;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002238
willy tarreaudfece232006-05-02 00:19:57 +02002239 if (!(s->flags & SN_ASSIGNED)) {
2240 if ((s->proxy->options & PR_O_BALANCE) && !(s->flags & SN_DIRECT)) {
2241 if (!s->proxy->srv_act && !s->proxy->srv_bck)
2242 return SRV_STATUS_NOSRV;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002243
willy tarreaudfece232006-05-02 00:19:57 +02002244 if (s->proxy->options & PR_O_BALANCE_RR) {
2245 s->srv = get_server_rr_with_conns(s->proxy);
2246 if (!s->srv)
2247 return SRV_STATUS_FULL;
2248 }
2249 else if (s->proxy->options & PR_O_BALANCE_SH) {
2250 int len;
2251
2252 if (s->cli_addr.ss_family == AF_INET)
2253 len = 4;
2254 else if (s->cli_addr.ss_family == AF_INET6)
2255 len = 16;
2256 else /* unknown IP family */
2257 return SRV_STATUS_INTERNAL;
2258
2259 s->srv = get_server_sh(s->proxy,
2260 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2261 len);
2262 }
2263 else /* unknown balancing algorithm */
2264 return SRV_STATUS_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002265 }
willy tarreaudfece232006-05-02 00:19:57 +02002266 s->flags |= SN_ASSIGNED;
2267 }
2268 return SRV_STATUS_OK;
2269}
willy tarreau1a3442d2006-03-24 21:03:20 +01002270
willy tarreaudfece232006-05-02 00:19:57 +02002271/*
2272 * This function assigns a server address to a session, and sets SN_ADDR_SET.
2273 * The address is taken from the currently assigned server, or from the
2274 * dispatch or transparent address.
2275 *
2276 * It may return :
2277 * SRV_STATUS_OK if everything is OK.
2278 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2279 *
2280 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
2281 * not cleared, so it's to the caller to clear it if required.
2282 *
2283 */
2284int assign_server_address(struct session *s) {
2285#ifdef DEBUG_FULL
2286 fprintf(stderr,"assign_server_address : s=%p\n",s);
2287#endif
2288
2289 if (s->flags & SN_DIRECT || s->proxy->options & PR_O_BALANCE) {
2290 /* A server is necessarily known for this session */
2291 if (!(s->flags & SN_ASSIGNED))
2292 return SRV_STATUS_INTERNAL;
2293
2294 s->srv_addr = s->srv->addr;
willy tarreau1a3442d2006-03-24 21:03:20 +01002295
willy tarreaudfece232006-05-02 00:19:57 +02002296 /* if this server remaps proxied ports, we'll use
2297 * the port the client connected to with an offset. */
2298 if (s->srv->state & SRV_MAPPORTS) {
2299 struct sockaddr_in sockname;
2300 socklen_t namelen = sizeof(sockname);
2301
2302 if (!(s->proxy->options & PR_O_TRANSP) ||
2303 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2304 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2305 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
willy tarreau1a3442d2006-03-24 21:03:20 +01002306 }
willy tarreau0f7af912005-12-17 12:21:26 +01002307 }
willy tarreaua1598082005-12-17 13:08:06 +01002308 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002309 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002310 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002311 }
2312 else if (s->proxy->options & PR_O_TRANSP) {
2313 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002314 socklen_t salen = sizeof(s->srv_addr);
2315
willy tarreau5cbea6f2005-12-17 12:48:26 +01002316 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2317 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaudfece232006-05-02 00:19:57 +02002318 return SRV_STATUS_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002319 }
2320 }
willy tarreau0f7af912005-12-17 12:21:26 +01002321
willy tarreaudfece232006-05-02 00:19:57 +02002322 s->flags |= SN_ADDR_SET;
2323 return SRV_STATUS_OK;
2324}
willy tarreaua41a8b42005-12-17 14:02:24 +01002325
willy tarreaudfece232006-05-02 00:19:57 +02002326/* This function assigns a server to session <s> if required, and can add the
2327 * connection to either the assigned server's queue or to the proxy's queue.
2328 *
2329 * Returns :
2330 *
2331 * SRV_STATUS_OK if everything is OK.
willy tarreau000375f2006-05-09 23:15:58 +02002332 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002333 * SRV_STATUS_QUEUED if the connection has been queued.
2334 * SRV_STATUS_FULL if the server(s) is/are saturated and the
2335 * connection could not be queued.
2336 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2337 *
2338 */
2339int assign_server_and_queue(struct session *s) {
2340 struct pendconn *p;
2341 int err;
2342
2343 if (s->pend_pos)
2344 return SRV_STATUS_INTERNAL;
2345
2346 if (s->flags & SN_ASSIGNED) {
2347 /* a server does not need to be assigned, perhaps because we're in
2348 * direct mode, or in dispatch or transparent modes where the server
2349 * is not needed.
2350 */
2351 if (s->srv &&
2352 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2353 p = pendconn_add(s);
2354 if (p)
2355 return SRV_STATUS_QUEUED;
2356 else
2357 return SRV_STATUS_FULL;
2358 }
2359 return SRV_STATUS_OK;
2360 }
2361
2362 /* a server needs to be assigned */
2363 err = assign_server(s);
2364 switch (err) {
2365 case SRV_STATUS_OK:
2366 /* in balance mode, we might have servers with connection limits */
2367 if (s->srv != NULL &&
2368 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2369 p = pendconn_add(s);
2370 if (p)
2371 return SRV_STATUS_QUEUED;
2372 else
2373 return SRV_STATUS_FULL;
2374 }
2375 return SRV_STATUS_OK;
2376
2377 case SRV_STATUS_FULL:
2378 /* queue this session into the proxy's queue */
2379 p = pendconn_add(s);
2380 if (p)
2381 return SRV_STATUS_QUEUED;
2382 else
2383 return SRV_STATUS_FULL;
2384
2385 case SRV_STATUS_NOSRV:
2386 case SRV_STATUS_INTERNAL:
2387 return err;
2388 default:
2389 return SRV_STATUS_INTERNAL;
willy tarreaua41a8b42005-12-17 14:02:24 +01002390 }
willy tarreaudfece232006-05-02 00:19:57 +02002391}
2392
2393
2394/*
2395 * This function initiates a connection to the server assigned to this session
2396 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
2397 * It can return one of :
2398 * - SN_ERR_NONE if everything's OK
2399 * - SN_ERR_SRVTO if there are no more servers
2400 * - SN_ERR_SRVCL if the connection was refused by the server
2401 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
2402 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
2403 * - SN_ERR_INTERNAL for any other purely internal errors
2404 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
2405 */
2406int connect_server(struct session *s) {
2407 int fd, err;
2408
2409 if (!(s->flags & SN_ADDR_SET)) {
2410 err = assign_server_address(s);
2411 if (err != SRV_STATUS_OK)
2412 return SN_ERR_INTERNAL;
2413 }
willy tarreaua41a8b42005-12-17 14:02:24 +01002414
willy tarreau0f7af912005-12-17 12:21:26 +01002415 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002416 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002417
2418 if (errno == ENFILE)
2419 send_log(s->proxy, LOG_EMERG,
2420 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2421 s->proxy->id, maxfd);
2422 else if (errno == EMFILE)
2423 send_log(s->proxy, LOG_EMERG,
2424 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2425 s->proxy->id, maxfd);
2426 else if (errno == ENOBUFS || errno == ENOMEM)
2427 send_log(s->proxy, LOG_EMERG,
2428 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2429 s->proxy->id, maxfd);
2430 /* this is a resource error */
2431 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002432 }
2433
willy tarreau9fe663a2005-12-17 13:02:59 +01002434 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002435 /* do not log anything there, it's a normal condition when this option
2436 * is used to serialize connections to a server !
2437 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002438 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2439 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002440 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002441 }
2442
willy tarreau0f7af912005-12-17 12:21:26 +01002443 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2444 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002445 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002446 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002447 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002448 }
2449
willy tarreaub952e1d2005-12-18 01:31:20 +01002450 if (s->proxy->options & PR_O_TCP_SRV_KA)
2451 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2452
willy tarreau0174f312005-12-18 01:02:42 +01002453 /* allow specific binding :
2454 * - server-specific at first
2455 * - proxy-specific next
2456 */
2457 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2458 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2459 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2460 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2461 s->proxy->id, s->srv->id);
2462 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002463 send_log(s->proxy, LOG_EMERG,
2464 "Cannot bind to source address before connect() for server %s/%s.\n",
2465 s->proxy->id, s->srv->id);
2466 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002467 }
2468 }
2469 else if (s->proxy->options & PR_O_BIND_SRC) {
2470 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2471 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2472 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2473 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002474 send_log(s->proxy, LOG_EMERG,
2475 "Cannot bind to source address before connect() for server %s/%s.\n",
2476 s->proxy->id, s->srv->id);
2477 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002478 }
willy tarreaua1598082005-12-17 13:08:06 +01002479 }
2480
willy tarreaub1285d52005-12-18 01:20:14 +01002481 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2482 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2483
2484 if (errno == EAGAIN || errno == EADDRINUSE) {
2485 char *msg;
2486 if (errno == EAGAIN) /* no free ports left, try again later */
2487 msg = "no free ports";
2488 else
2489 msg = "local address already in use";
2490
2491 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002492 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002493 send_log(s->proxy, LOG_EMERG,
2494 "Connect() failed for server %s/%s: %s.\n",
2495 s->proxy->id, s->srv->id, msg);
2496 return SN_ERR_RESOURCE;
2497 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002498 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002499 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002500 return SN_ERR_SRVTO;
2501 } else {
2502 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002503 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002504 close(fd);
2505 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002506 }
2507 }
2508
willy tarreau5cbea6f2005-12-17 12:48:26 +01002509 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002510 fdtab[fd].read = &event_srv_read;
2511 fdtab[fd].write = &event_srv_write;
2512 fdtab[fd].state = FD_STCONN; /* connection in progress */
2513
2514 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002515#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2516 if (PrevReadEvent) {
2517 assert(!(FD_ISSET(fd, PrevReadEvent)));
2518 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2519 }
2520#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002521
2522 fd_insert(fd);
willy tarreaucb406512006-05-18 00:52:35 +02002523 if (s->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02002524 s->srv->cur_sess++;
willy tarreaucb406512006-05-18 00:52:35 +02002525 if (s->srv->cur_sess > s->srv->cur_sess_max)
2526 s->srv->cur_sess_max = s->srv->cur_sess;
2527 }
willy tarreau0f7af912005-12-17 12:21:26 +01002528
2529 if (s->proxy->contimeout)
2530 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2531 else
2532 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002533 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002534}
2535
2536/*
2537 * this function is called on a read event from a client socket.
2538 * It returns 0.
2539 */
2540int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002541 struct task *t = fdtab[fd].owner;
2542 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002543 struct buffer *b = s->req;
2544 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002545
willy tarreau12350152005-12-18 01:03:27 +01002546#ifdef DEBUG_FULL
2547 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2548#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002549
willy tarreau0f7af912005-12-17 12:21:26 +01002550 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002551#ifdef FILL_BUFFERS
2552 while (1)
2553#else
2554 do
2555#endif
2556 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002557 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2558 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002559 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002560 }
2561 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002562 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002563 }
2564 else {
2565 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002566 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2567 * since it means that the rewrite protection has been removed. This
2568 * implies that the if statement can be removed.
2569 */
2570 if (max > b->rlim - b->data)
2571 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002572 }
2573
2574 if (max == 0) { /* not anymore room to store data */
2575 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002576 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002577 }
2578
willy tarreau3242e862005-12-17 12:27:53 +01002579#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002580 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002581 int skerr;
2582 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002583
willy tarreau5cbea6f2005-12-17 12:48:26 +01002584 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2585 if (skerr)
2586 ret = -1;
2587 else
2588 ret = recv(fd, b->r, max, 0);
2589 }
willy tarreau3242e862005-12-17 12:27:53 +01002590#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002591 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002592#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002593 if (ret > 0) {
2594 b->r += ret;
2595 b->l += ret;
2596 s->res_cr = RES_DATA;
2597
2598 if (b->r == b->data + BUFSIZE) {
2599 b->r = b->data; /* wrap around the buffer */
2600 }
willy tarreaua1598082005-12-17 13:08:06 +01002601
2602 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002603 /* we hope to read more data or to get a close on next round */
2604 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002605 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002606 else if (ret == 0) {
2607 s->res_cr = RES_NULL;
2608 break;
2609 }
2610 else if (errno == EAGAIN) {/* ignore EAGAIN */
2611 break;
2612 }
2613 else {
2614 s->res_cr = RES_ERROR;
2615 fdtab[fd].state = FD_STERROR;
2616 break;
2617 }
2618 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002619#ifndef FILL_BUFFERS
2620 while (0);
2621#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002622 }
2623 else {
2624 s->res_cr = RES_ERROR;
2625 fdtab[fd].state = FD_STERROR;
2626 }
2627
willy tarreau5cbea6f2005-12-17 12:48:26 +01002628 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002629 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002630 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2631 else
2632 tv_eternity(&s->crexpire);
2633
2634 task_wakeup(&rq, t);
2635 }
willy tarreau0f7af912005-12-17 12:21:26 +01002636
willy tarreau0f7af912005-12-17 12:21:26 +01002637 return 0;
2638}
2639
2640
2641/*
2642 * this function is called on a read event from a server socket.
2643 * It returns 0.
2644 */
2645int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002646 struct task *t = fdtab[fd].owner;
2647 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002648 struct buffer *b = s->rep;
2649 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002650
willy tarreau12350152005-12-18 01:03:27 +01002651#ifdef DEBUG_FULL
2652 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2653#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002654
willy tarreau0f7af912005-12-17 12:21:26 +01002655 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002656#ifdef FILL_BUFFERS
2657 while (1)
2658#else
2659 do
2660#endif
2661 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002662 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2663 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002664 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002665 }
2666 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002667 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002668 }
2669 else {
2670 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002671 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2672 * since it means that the rewrite protection has been removed. This
2673 * implies that the if statement can be removed.
2674 */
2675 if (max > b->rlim - b->data)
2676 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002677 }
2678
2679 if (max == 0) { /* not anymore room to store data */
2680 FD_CLR(fd, StaticReadEvent);
2681 break;
2682 }
2683
willy tarreau3242e862005-12-17 12:27:53 +01002684#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002685 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002686 int skerr;
2687 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002688
willy tarreau5cbea6f2005-12-17 12:48:26 +01002689 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2690 if (skerr)
2691 ret = -1;
2692 else
2693 ret = recv(fd, b->r, max, 0);
2694 }
willy tarreau3242e862005-12-17 12:27:53 +01002695#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002696 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002697#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002698 if (ret > 0) {
2699 b->r += ret;
2700 b->l += ret;
2701 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002702
willy tarreau5cbea6f2005-12-17 12:48:26 +01002703 if (b->r == b->data + BUFSIZE) {
2704 b->r = b->data; /* wrap around the buffer */
2705 }
willy tarreaua1598082005-12-17 13:08:06 +01002706
2707 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002708 /* we hope to read more data or to get a close on next round */
2709 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002710 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002711 else if (ret == 0) {
2712 s->res_sr = RES_NULL;
2713 break;
2714 }
2715 else if (errno == EAGAIN) {/* ignore EAGAIN */
2716 break;
2717 }
2718 else {
2719 s->res_sr = RES_ERROR;
2720 fdtab[fd].state = FD_STERROR;
2721 break;
2722 }
2723 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002724#ifndef FILL_BUFFERS
2725 while (0);
2726#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002727 }
2728 else {
2729 s->res_sr = RES_ERROR;
2730 fdtab[fd].state = FD_STERROR;
2731 }
2732
willy tarreau5cbea6f2005-12-17 12:48:26 +01002733 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002734 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002735 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2736 else
2737 tv_eternity(&s->srexpire);
2738
2739 task_wakeup(&rq, t);
2740 }
willy tarreau0f7af912005-12-17 12:21:26 +01002741
willy tarreau0f7af912005-12-17 12:21:26 +01002742 return 0;
2743}
2744
2745/*
2746 * this function is called on a write event from a client socket.
2747 * It returns 0.
2748 */
2749int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002750 struct task *t = fdtab[fd].owner;
2751 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002752 struct buffer *b = s->rep;
2753 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002754
willy tarreau12350152005-12-18 01:03:27 +01002755#ifdef DEBUG_FULL
2756 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2757#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002758
2759 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002760 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002761 // max = BUFSIZE; BUG !!!!
2762 max = 0;
2763 }
2764 else if (b->r > b->w) {
2765 max = b->r - b->w;
2766 }
2767 else
2768 max = b->data + BUFSIZE - b->w;
2769
willy tarreau0f7af912005-12-17 12:21:26 +01002770 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002771 if (max == 0) {
2772 s->res_cw = RES_NULL;
2773 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002774 tv_eternity(&s->cwexpire);
2775 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002776 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002777 }
2778
willy tarreau3242e862005-12-17 12:27:53 +01002779#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002780 {
2781 int skerr;
2782 socklen_t lskerr = sizeof(skerr);
2783
2784 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2785 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002786 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002787 else
willy tarreau3242e862005-12-17 12:27:53 +01002788 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002789 }
willy tarreau3242e862005-12-17 12:27:53 +01002790#else
willy tarreau0f7af912005-12-17 12:21:26 +01002791 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002792#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002793
2794 if (ret > 0) {
2795 b->l -= ret;
2796 b->w += ret;
2797
2798 s->res_cw = RES_DATA;
2799
2800 if (b->w == b->data + BUFSIZE) {
2801 b->w = b->data; /* wrap around the buffer */
2802 }
2803 }
2804 else if (ret == 0) {
2805 /* nothing written, just make as if we were never called */
2806// s->res_cw = RES_NULL;
2807 return 0;
2808 }
2809 else if (errno == EAGAIN) /* ignore EAGAIN */
2810 return 0;
2811 else {
2812 s->res_cw = RES_ERROR;
2813 fdtab[fd].state = FD_STERROR;
2814 }
2815 }
2816 else {
2817 s->res_cw = RES_ERROR;
2818 fdtab[fd].state = FD_STERROR;
2819 }
2820
willy tarreaub1ff9db2005-12-17 13:51:03 +01002821 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002822 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002823 /* FIXME: to prevent the client from expiring read timeouts during writes,
2824 * we refresh it. A solution would be to merge read+write timeouts into a
2825 * unique one, although that needs some study particularly on full-duplex
2826 * TCP connections. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002827 s->crexpire = s->cwexpire;
2828 }
willy tarreau0f7af912005-12-17 12:21:26 +01002829 else
2830 tv_eternity(&s->cwexpire);
2831
willy tarreau5cbea6f2005-12-17 12:48:26 +01002832 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002833 return 0;
2834}
2835
2836
2837/*
2838 * this function is called on a write event from a server socket.
2839 * It returns 0.
2840 */
2841int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002842 struct task *t = fdtab[fd].owner;
2843 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002844 struct buffer *b = s->req;
2845 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002846
willy tarreau12350152005-12-18 01:03:27 +01002847#ifdef DEBUG_FULL
2848 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2849#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002850
2851 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002852 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002853 // max = BUFSIZE; BUG !!!!
2854 max = 0;
2855 }
2856 else if (b->r > b->w) {
2857 max = b->r - b->w;
2858 }
2859 else
2860 max = b->data + BUFSIZE - b->w;
2861
willy tarreau0f7af912005-12-17 12:21:26 +01002862 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002863 if (max == 0) {
2864 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002865 if (s->srv_state == SV_STCONN) {
2866 int skerr;
2867 socklen_t lskerr = sizeof(skerr);
2868 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2869 if (skerr) {
2870 s->res_sw = RES_ERROR;
2871 fdtab[fd].state = FD_STERROR;
2872 task_wakeup(&rq, t);
2873 tv_eternity(&s->swexpire);
2874 FD_CLR(fd, StaticWriteEvent);
2875 return 0;
2876 }
2877 }
2878
willy tarreau0f7af912005-12-17 12:21:26 +01002879 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002880 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002881 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002882 tv_eternity(&s->swexpire);
2883 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002884 return 0;
2885 }
2886
willy tarreau3242e862005-12-17 12:27:53 +01002887#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002888 {
2889 int skerr;
2890 socklen_t lskerr = sizeof(skerr);
2891 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2892 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002893 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002894 else
willy tarreau3242e862005-12-17 12:27:53 +01002895 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002896 }
willy tarreau3242e862005-12-17 12:27:53 +01002897#else
willy tarreau0f7af912005-12-17 12:21:26 +01002898 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002899#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002900 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002901 if (ret > 0) {
2902 b->l -= ret;
2903 b->w += ret;
2904
2905 s->res_sw = RES_DATA;
2906
2907 if (b->w == b->data + BUFSIZE) {
2908 b->w = b->data; /* wrap around the buffer */
2909 }
2910 }
2911 else if (ret == 0) {
2912 /* nothing written, just make as if we were never called */
2913 // s->res_sw = RES_NULL;
2914 return 0;
2915 }
2916 else if (errno == EAGAIN) /* ignore EAGAIN */
2917 return 0;
2918 else {
2919 s->res_sw = RES_ERROR;
2920 fdtab[fd].state = FD_STERROR;
2921 }
2922 }
2923 else {
2924 s->res_sw = RES_ERROR;
2925 fdtab[fd].state = FD_STERROR;
2926 }
2927
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002928 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2929 * otherwise it could loop indefinitely !
2930 */
2931 if (s->srv_state != SV_STCONN) {
2932 if (s->proxy->srvtimeout) {
2933 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002934 /* FIXME: to prevent the server from expiring read timeouts during writes,
2935 * we refresh it. A solution would be to merge read+write+connect timeouts
2936 * into a unique one since we don't mind expiring on read or write, and none
2937 * of them is enabled while waiting for connect(), although that needs some
2938 * study particularly on full-duplex TCP connections. */
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002939 s->srexpire = s->swexpire;
2940 }
2941 else
2942 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002943 }
willy tarreau0f7af912005-12-17 12:21:26 +01002944
willy tarreau5cbea6f2005-12-17 12:48:26 +01002945 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002946 return 0;
2947}
2948
2949
willy tarreaue0331262006-05-15 03:02:46 +02002950/* returns 1 if the buffer is empty, 0 otherwise */
2951static inline int buffer_isempty(struct buffer *buf) {
2952 return buf->l == 0;
2953}
2954
2955
2956/* returns 1 if the buffer is full, 0 otherwise */
2957static inline int buffer_isfull(struct buffer *buf) {
2958 return buf->l == BUFSIZE;
2959}
2960
2961
2962/* flushes any content from buffer <buf> */
2963void buffer_flush(struct buffer *buf) {
2964 buf->r = buf->h = buf->lr = buf->w = buf->data;
2965 buf->l = 0;
2966}
2967
2968
2969/* returns the maximum number of bytes writable at once in this buffer */
2970int buffer_max(struct buffer *buf) {
willy tarreaucb406512006-05-18 00:52:35 +02002971 if (buf->l == BUFSIZE)
2972 return 0;
2973 else if (buf->r >= buf->w)
willy tarreaue0331262006-05-15 03:02:46 +02002974 return buf->data + BUFSIZE - buf->r;
2975 else
2976 return buf->w - buf->r;
2977}
2978
2979
willy tarreau0f7af912005-12-17 12:21:26 +01002980/*
willy tarreaue0331262006-05-15 03:02:46 +02002981 * Tries to realign the given buffer, and returns how many bytes can be written
2982 * there at once without overwriting anything.
2983 */
2984int buffer_realign(struct buffer *buf) {
2985 if (buf->l == 0) {
2986 /* let's realign the buffer to optimize I/O */
willy tarreaucb406512006-05-18 00:52:35 +02002987 buf->r = buf->w = buf->h = buf->lr = buf->data;
willy tarreaue0331262006-05-15 03:02:46 +02002988 }
2989 return buffer_max(buf);
2990}
2991
2992
2993/* writes <len> bytes from message <msg> to buffer <buf>. Returns 0 in case of
2994 * success, or the number of bytes available otherwise.
willy tarreau1f431b52006-05-21 14:46:15 +02002995 * FIXME-20060521: handle unaligned data.
willy tarreaue0331262006-05-15 03:02:46 +02002996 */
2997int buffer_write(struct buffer *buf, const char *msg, int len) {
2998 int max;
2999
willy tarreaucb406512006-05-18 00:52:35 +02003000 max = buffer_realign(buf);
willy tarreaue0331262006-05-15 03:02:46 +02003001
3002 if (len > max)
3003 return max;
3004
3005 memcpy(buf->r, msg, len);
3006 buf->l += len;
3007 buf->r += len;
3008 if (buf->r == buf->data + BUFSIZE)
willy tarreaucb406512006-05-18 00:52:35 +02003009 buf->r = buf->data;
willy tarreaue0331262006-05-15 03:02:46 +02003010 return 0;
3011}
3012
3013
3014/*
willy tarreaue39cd132005-12-17 13:00:18 +01003015 * returns a message to the client ; the connection is shut down for read,
3016 * and the request is cleared so that no server connection can be initiated.
3017 * The client must be in a valid state for this (HEADER, DATA ...).
3018 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01003019 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01003020 */
3021void client_retnclose(struct session *s, int len, const char *msg) {
3022 FD_CLR(s->cli_fd, StaticReadEvent);
3023 FD_SET(s->cli_fd, StaticWriteEvent);
3024 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01003025 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01003026 shutdown(s->cli_fd, SHUT_RD);
3027 s->cli_state = CL_STSHUTR;
willy tarreaue0331262006-05-15 03:02:46 +02003028 buffer_flush(s->rep);
3029 buffer_write(s->rep, msg, len);
willy tarreaue39cd132005-12-17 13:00:18 +01003030 s->req->l = 0;
3031}
3032
3033
3034/*
3035 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01003036 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01003037 */
3038void client_return(struct session *s, int len, const char *msg) {
willy tarreaue0331262006-05-15 03:02:46 +02003039 buffer_flush(s->rep);
3040 buffer_write(s->rep, msg, len);
willy tarreaue39cd132005-12-17 13:00:18 +01003041 s->req->l = 0;
3042}
3043
willy tarreaue0331262006-05-15 03:02:46 +02003044/*
3045 * Produces data for the session <s> depending on its source. Expects to be
3046 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3047 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3048 * session, which it uses to keep on being called when there is free space in
3049 * the buffer, of simply by letting an empty buffer upon return. It returns 1
3050 * if it changes the session state from CL_STSHUTR, otherwise 0.
3051 */
3052int produce_content(struct session *s) {
3053 struct buffer *rep = s->rep;
3054 struct proxy *px;
3055 struct server *sv;
willy tarreaucb406512006-05-18 00:52:35 +02003056 int msglen;
willy tarreaue0331262006-05-15 03:02:46 +02003057
3058 if (s->data_source == DATA_SRC_NONE) {
3059 s->flags &= ~SN_SELF_GEN;
3060 return 1;
3061 }
3062 else if (s->data_source == DATA_SRC_STATS) {
willy tarreau1f431b52006-05-21 14:46:15 +02003063 msglen = 0;
3064
3065 if (s->data_state == DATA_ST_INIT) { /* the function had not been called yet */
3066 unsigned int up;
3067
willy tarreaue0331262006-05-15 03:02:46 +02003068 s->flags |= SN_SELF_GEN; // more data will follow
willy tarreau1f431b52006-05-21 14:46:15 +02003069
3070 /* send the start of the HTTP response */
3071 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003072 "HTTP/1.0 200 OK\r\n"
3073 "Cache-Control: no-cache\r\n"
3074 "Connection: close\r\n"
3075 "\r\n\r\n");
3076
3077 s->logs.status = 200;
3078 client_retnclose(s, msglen, trash); // send the start of the response.
willy tarreau1f431b52006-05-21 14:46:15 +02003079 msglen = 0;
3080
willy tarreaue0331262006-05-15 03:02:46 +02003081 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
3082 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
3083 if (!(s->flags & SN_FINST_MASK))
3084 s->flags |= SN_FINST_R;
3085
3086 /* WARNING! This must fit in the first buffer !!! */
willy tarreau1f431b52006-05-21 14:46:15 +02003087 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003088 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
3089 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
3090 "<style type=\"text/css\"><!--\n"
3091 "body {"
3092 " font-family: helvetica, arial;"
3093 " font-size: 12px;"
3094 " font-weight: normal;"
3095 " color: black;"
3096 " background: white;"
3097 "}\n"
3098 "td {"
3099 " font-size: 12px;"
willy tarreaucb406512006-05-18 00:52:35 +02003100 " align: center;"
willy tarreaue0331262006-05-15 03:02:46 +02003101 "}\n"
3102 "h1 {"
3103 " font-size: xx-large;"
3104 " margin-bottom: 0.5em;"
3105 "}\n"
3106 "h2 {"
3107 " font-family: helvetica, arial;"
3108 " font-size: x-large;"
3109 " font-weight: bold;"
3110 " font-style: italic;"
3111 " color: #6020a0;"
3112 " margin-top: 0em;"
3113 " margin-bottom: 0em;"
3114 "}\n"
3115 "h3 {"
3116 " font-family: helvetica, arial;"
3117 " font-size: 16px;"
3118 " font-weight: bold;"
3119 " color: #b00040;"
3120 " background: #e8e8d0;"
3121 " margin-top: 0em;"
3122 " margin-bottom: 0em;"
3123 "}\n"
3124 "li {"
3125 " margin-top: 0.25em;"
3126 " margin-right: 2em;"
3127 "}\n"
3128 ".hr {"
3129 " margin-top: 0.25em;"
3130 " border-color: black;"
3131 " border-bottom-style: solid;"
willy tarreaucb406512006-05-18 00:52:35 +02003132 "}\n"
3133 "table.tbl { border-collapse: collapse; border-width: 1px; border-style: solid; border-color: gray;}\n"
3134 "table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; border-color: gray; }\n"
3135 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray; }\n"
3136 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
3137 "table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n"
willy tarreaue0331262006-05-15 03:02:46 +02003138 "-->"
3139 "</style></head>");
3140
willy tarreaucb406512006-05-18 00:52:35 +02003141 if (buffer_write(rep, trash, msglen) != 0)
3142 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003143 msglen = 0;
willy tarreaue0331262006-05-15 03:02:46 +02003144
3145 up = (now.tv_sec - start_date.tv_sec);
3146
3147 /* WARNING! this has to fit the first packet too */
willy tarreau1f431b52006-05-21 14:46:15 +02003148 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003149 "<body><h1>" PRODUCT_NAME "</h1>\n"
3150 "<h2>Statistics Report for pid %d</h2>\n"
3151 "<hr width=\"100%%\" class=\"hr\">\n"
willy tarreau338be832006-05-21 08:58:06 +02003152 "<h3>&gt; General process information</h3>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003153 "<table border=0><tr><td align=\"left\">\n"
willy tarreaue0331262006-05-15 03:02:46 +02003154 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
3155 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
willy tarreau338be832006-05-21 08:58:06 +02003156 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
willy tarreaue0331262006-05-15 03:02:46 +02003157 "<b>maxsock = </b> %d<br>\n"
3158 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003159 "</td><td width=\"10%%\">\n"
3160 "</td><td align=\"right\">\n"
3161 "<table class=\"lgd\">"
3162 "<tr><td bgcolor=\"#C0FFC0\">&nbsp;</td><td style=\"border-style: none;\">active UP </td>"
3163 "<td bgcolor=\"#B0D0FF\">&nbsp;</td><td style=\"border-style: none;\">backup UP </td></tr>"
3164 "<tr><td bgcolor=\"#FFFFA0\"></td><td style=\"border-style: none;\">active UP, going down </td>"
3165 "<td bgcolor=\"#C060FF\"></td><td style=\"border-style: none;\">backup UP, going down </td></tr>"
3166 "<tr><td bgcolor=\"#FFD020\"></td><td style=\"border-style: none;\">active DOWN, going up </td>"
3167 "<td bgcolor=\"#FF80FF\"></td><td style=\"border-style: none;\">backup DOWN, going up </td></tr>"
3168 "<tr><td bgcolor=\"#FF9090\"></td><td style=\"border-style: none;\">active or backup DOWN &nbsp;</td>"
3169 "<td bgcolor=\"#E0E0E0\"></td><td style=\"border-style: none;\">not checked </td></tr>"
3170 "</table>\n"
3171 "</tr></table>\n"
willy tarreaue0331262006-05-15 03:02:46 +02003172 "",
3173 pid, pid, global.nbproc,
3174 up / 86400, (up % 86400) / 3600,
3175 (up % 3600) / 60, (up % 60),
willy tarreau338be832006-05-21 08:58:06 +02003176 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
3177 global.rlimit_memmax ? " MB" : "",
willy tarreaue0331262006-05-15 03:02:46 +02003178 global.rlimit_nofile,
3179 global.maxsock,
3180 global.maxconn,
3181 actconn
3182 );
willy tarreaucb406512006-05-18 00:52:35 +02003183
3184 if (buffer_write(rep, trash, msglen) != 0)
3185 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003186 msglen = 0;
3187
3188 s->data_state = DATA_ST_DATA;
3189 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
3190
willy tarreaue0331262006-05-15 03:02:46 +02003191 px = s->data_ctx.stats.px = proxy;
willy tarreau1f431b52006-05-21 14:46:15 +02003192 s->data_ctx.stats.px_st = DATA_ST_INIT;
willy tarreaue0331262006-05-15 03:02:46 +02003193 }
3194
3195 while (s->data_ctx.stats.px) {
willy tarreaucb406512006-05-18 00:52:35 +02003196 int dispatch_sess, dispatch_cum;
willy tarreau1f431b52006-05-21 14:46:15 +02003197 int failed_checks, down_trans;
willy tarreaue3b30652006-05-21 16:23:22 +02003198 int failed_secu, failed_conns, failed_resp;
willy tarreaucb406512006-05-18 00:52:35 +02003199
willy tarreau1f431b52006-05-21 14:46:15 +02003200 if (s->data_ctx.stats.px_st == DATA_ST_INIT) {
3201 /* we are on a new proxy */
willy tarreaue0331262006-05-15 03:02:46 +02003202 px = s->data_ctx.stats.px;
willy tarreau1f431b52006-05-21 14:46:15 +02003203
3204 /* skip the disabled proxies */
3205 if (px->state == PR_STSTOPPED)
3206 goto next_proxy;
3207
3208 if (s->proxy->uri_auth && s->proxy->uri_auth->scope) {
3209 /* we have a limited scope, we have to check the proxy name */
3210 struct stat_scope *scope;
3211 int len;
3212
3213 len = strlen(px->id);
3214 scope = s->proxy->uri_auth->scope;
3215
3216 while (scope) {
3217 /* match exact proxy name */
3218 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
3219 break;
3220
3221 /* match '.' which means 'self' proxy */
3222 if (!strcmp(scope->px_id, ".") && px == s->proxy)
3223 break;
3224 scope = scope->next;
3225 }
3226
3227 /* proxy name not found */
3228 if (scope == NULL)
3229 goto next_proxy;
3230 }
3231
3232 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003233 "<h3>&gt; Proxy instance %s : "
3234 "%d conns (maxconn=%d), %d queued (%d unassigned), %d total conns</h3>\n"
3235 "",
3236 px->id,
3237 px->nbconn, px->maxconn, px->totpend, px->nbpend, px->cum_conn);
3238
3239 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue3b30652006-05-21 16:23:22 +02003240 "<table cols=\"16\" class=\"tbl\">\n"
willy tarreaucb406512006-05-18 00:52:35 +02003241 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
3242 "<th colspan=5>Server</th>"
3243 "<th colspan=2>Queue</th>"
3244 "<th colspan=4>Sessions</th>"
willy tarreaue3b30652006-05-21 16:23:22 +02003245 "<th colspan=5>Errors</th></tr>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003246 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
3247 "<th>Name</th><th>Weight</th><th>Status</th><th>Act.</th><th>Bck.</th>"
3248 "<th>Curr.</th><th>Max.</th>"
3249 "<th>Curr.</th><th>Max.</th><th>Limit</th><th>Cumul.</th>"
willy tarreaue3b30652006-05-21 16:23:22 +02003250 "<th>Conn.</th><th>Resp.</th><th>Sec.</th><th>Check</th><th>Down</th></tr>\n");
willy tarreaue0331262006-05-15 03:02:46 +02003251
3252 if (buffer_write(rep, trash, msglen) != 0)
3253 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003254 msglen = 0;
3255
willy tarreaue0331262006-05-15 03:02:46 +02003256 s->data_ctx.stats.sv = px->srv;
willy tarreau1f431b52006-05-21 14:46:15 +02003257 s->data_ctx.stats.px_st = DATA_ST_DATA;
willy tarreaue0331262006-05-15 03:02:46 +02003258 }
3259
willy tarreaucb406512006-05-18 00:52:35 +02003260 px = s->data_ctx.stats.px;
3261
willy tarreau1f431b52006-05-21 14:46:15 +02003262 /* stats.sv has been initialized above */
willy tarreaue0331262006-05-15 03:02:46 +02003263 while (s->data_ctx.stats.sv != NULL) {
willy tarreaucb406512006-05-18 00:52:35 +02003264 static char *act_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FFD020", /*failing*/"#FFFFA0", /*up*/"#C0FFC0", /*unchecked*/"#E0E0E0" };
3265 static char *bck_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FF80ff", /*failing*/"#C060FF", /*up*/"#B0D0FF", /*unchecked*/"#E0E0E0" };
3266 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
3267 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP */
3268
willy tarreaue0331262006-05-15 03:02:46 +02003269 sv = s->data_ctx.stats.sv;
willy tarreaucb406512006-05-18 00:52:35 +02003270
willy tarreaucb406512006-05-18 00:52:35 +02003271 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
3272 if (!(sv->state & SRV_CHECKED))
3273 sv_state = 4;
3274 else if (sv->state & SRV_RUNNING)
3275 if (sv->health == sv->rise + sv->fall - 1)
3276 sv_state = 3; /* UP */
3277 else
3278 sv_state = 2; /* going down */
3279 else
3280 if (sv->health)
3281 sv_state = 1; /* going up */
3282 else
3283 sv_state = 0; /* DOWN */
3284
3285 /* name, weight */
willy tarreau1f431b52006-05-21 14:46:15 +02003286 msglen += snprintf(trash, sizeof(trash),
willy tarreaucb406512006-05-18 00:52:35 +02003287 "<tr align=center bgcolor=\"%s\"><td>%s</td><td>%d</td><td>",
3288 (sv->state & SRV_BACKUP) ? bck_tab_bg[sv_state] : act_tab_bg[sv_state],
3289 sv->id, sv->uweight+1);
3290 /* status */
3291 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, srv_hlt_st[sv_state],
3292 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
3293 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
3294
3295 /* act, bck */
3296 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3297 "</td><td>%s</td><td>%s</td>",
willy tarreaue0331262006-05-15 03:02:46 +02003298 (sv->state & SRV_BACKUP) ? "-" : "Y",
3299 (sv->state & SRV_BACKUP) ? "Y" : "-");
willy tarreaucb406512006-05-18 00:52:35 +02003300
3301 /* queue : current, max */
3302 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3303 "<td align=right>%d</td><td align=right>%d</td>",
3304 sv->nbpend, sv->nbpend_max);
3305
3306 /* sessions : current, max, limit, cumul */
3307 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3308 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>",
3309 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess);
3310
willy tarreaue3b30652006-05-21 16:23:22 +02003311 /* errors : connect, response, security */
3312 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3313 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3314 sv->failed_conns, sv->failed_resp, sv->failed_secu);
3315
3316 /* check failures : unique, fatal */
willy tarreau338be832006-05-21 08:58:06 +02003317 if (sv->state & SRV_CHECKED)
3318 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3319 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3320 sv->failed_checks, sv->down_trans);
3321 else
3322 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3323 "<td align=right>-</td><td align=right>-</td></tr>\n");
willy tarreaucb406512006-05-18 00:52:35 +02003324
willy tarreau1f431b52006-05-21 14:46:15 +02003325 if (buffer_write(rep, trash, msglen) != 0)
3326 return 0;
3327 msglen = 0;
3328
3329 s->data_ctx.stats.sv = sv->next;
3330 } /* while sv */
3331
3332 /* now we are past the last server, we'll dump information about the dispatcher */
3333
3334 /* We have to count down from the proxy to the servers to tell how
3335 * many sessions are on the dispatcher, and how many checks have
3336 * failed. We cannot count this during the servers dump because it
3337 * might be interrupted multiple times.
3338 */
3339 dispatch_sess = px->nbconn;
willy tarreaue3b30652006-05-21 16:23:22 +02003340 dispatch_cum = px->cum_conn;
3341 failed_secu = px->failed_secu;
3342 failed_conns = px->failed_conns;
3343 failed_resp = px->failed_resp;
willy tarreau1f431b52006-05-21 14:46:15 +02003344 failed_checks = down_trans = 0;
3345
3346 sv = px->srv;
3347 while (sv) {
3348 dispatch_sess -= sv->cur_sess;
3349 dispatch_cum -= sv->cum_sess;
willy tarreaue3b30652006-05-21 16:23:22 +02003350 failed_conns -= sv->failed_conns;
3351 failed_resp -= sv->failed_resp;
3352 failed_secu -= sv->failed_secu;
3353 if (sv->state & SRV_CHECKED) {
3354 failed_checks += sv->failed_checks;
3355 down_trans += sv->down_trans;
3356 }
willy tarreaue0331262006-05-15 03:02:46 +02003357 sv = sv->next;
willy tarreau1f431b52006-05-21 14:46:15 +02003358 }
willy tarreaucb406512006-05-18 00:52:35 +02003359
willy tarreau1f431b52006-05-21 14:46:15 +02003360 /* name, weight, status, act, bck */
3361 msglen += snprintf(trash + msglen, sizeof(trash),
3362 "<tr align=center bgcolor=\"#e8e8d0\">"
3363 "<td>Dispatcher</td><td>-</td>"
3364 "<td>%s</td><td>-</td><td>-</td>",
3365 px->state == PR_STRUN ? "UP" : "DOWN");
willy tarreaucb406512006-05-18 00:52:35 +02003366
willy tarreau1f431b52006-05-21 14:46:15 +02003367 /* queue : current, max */
3368 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3369 "<td align=right>%d</td><td align=right>%d</td>",
3370 px->nbpend, px->nbpend_max);
willy tarreaucb406512006-05-18 00:52:35 +02003371
willy tarreau1f431b52006-05-21 14:46:15 +02003372 /* sessions : current, max, limit, cumul. */
3373 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3374 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>",
3375 dispatch_sess, px->nbconn_max, px->maxconn, dispatch_cum);
willy tarreaucb406512006-05-18 00:52:35 +02003376
willy tarreaue3b30652006-05-21 16:23:22 +02003377 /* errors : connect, response, security */
3378 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3379 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3380 failed_conns, failed_resp, failed_secu);
3381
3382 /* check failures : unique, fatal */
willy tarreau1f431b52006-05-21 14:46:15 +02003383 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3384 "<td align=right>-</td><td align=right>-</td></tr>\n");
willy tarreaucb406512006-05-18 00:52:35 +02003385
willy tarreaucb406512006-05-18 00:52:35 +02003386
willy tarreau1f431b52006-05-21 14:46:15 +02003387 /* now the summary for the whole proxy */
3388 /* name, weight, status, act, bck */
3389 msglen += snprintf(trash + msglen, sizeof(trash),
3390 "<tr align=center style=\"color: #ffff80; background: #20C0C0;\">"
3391 "<td><b>Total</b></td><td>-</td>"
3392 "<td><b>%s</b></td><td><b>%d</b></td><td><b>%d</b></td>",
3393 (px->state == PR_STRUN && ((px->srv == NULL) || px->srv_act || px->srv_bck)) ? "UP" : "DOWN",
3394 px->srv_act, px->srv_bck);
willy tarreaucb406512006-05-18 00:52:35 +02003395
willy tarreau1f431b52006-05-21 14:46:15 +02003396 /* queue : current, max */
3397 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3398 "<td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
3399 px->totpend, px->nbpend_max);
willy tarreaucb406512006-05-18 00:52:35 +02003400
willy tarreau1f431b52006-05-21 14:46:15 +02003401 /* sessions : current, max, limit, cumul */
3402 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3403 "<td align=right><b>%d</b></td><td align=right><b>%d</b></td><td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
3404 px->nbconn, px->nbconn_max, px->maxconn, px->cum_conn);
willy tarreaucb406512006-05-18 00:52:35 +02003405
willy tarreaue3b30652006-05-21 16:23:22 +02003406 /* errors : connect, response, security */
3407 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3408 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3409 px->failed_conns, px->failed_resp, px->failed_secu);
3410
3411 /* check failures : unique, fatal */
willy tarreau1f431b52006-05-21 14:46:15 +02003412 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3413 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3414 failed_checks, down_trans);
willy tarreaucb406512006-05-18 00:52:35 +02003415
willy tarreau1f431b52006-05-21 14:46:15 +02003416 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, "</table><p>\n");
3417
3418 if (buffer_write(rep, trash, msglen) != 0)
3419 return 0;
3420 msglen = 0;
3421
3422 s->data_ctx.stats.px_st = DATA_ST_INIT;
3423 next_proxy:
3424 s->data_ctx.stats.px = px->next;
willy tarreaucb406512006-05-18 00:52:35 +02003425 } /* proxy loop */
willy tarreaue0331262006-05-15 03:02:46 +02003426 /* here, we just have reached the sv == NULL and px == NULL */
3427 s->flags &= ~SN_SELF_GEN;
3428 return 1;
3429 }
3430 else {
3431 /* unknown data source */
3432 s->logs.status = 500;
3433 client_retnclose(s, s->proxy->errmsg.len500, s->proxy->errmsg.msg500);
3434 if (!(s->flags & SN_ERR_MASK))
3435 s->flags |= SN_ERR_PRXCOND;
3436 if (!(s->flags & SN_FINST_MASK))
3437 s->flags |= SN_FINST_R;
3438 s->flags &= SN_SELF_GEN;
3439 return 1;
3440 }
3441}
3442
3443
willy tarreau9fe663a2005-12-17 13:02:59 +01003444/*
3445 * send a log for the session when we have enough info about it
3446 */
3447void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003448 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01003449 struct proxy *p = s->proxy;
3450 int log;
3451 char *uri;
3452 char *pxid;
3453 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01003454 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01003455
3456 /* This is a first attempt at a better logging system.
3457 * For now, we rely on send_log() to provide the date, although it obviously
3458 * is the date of the log and not of the request, and most fields are not
3459 * computed.
3460 */
3461
willy tarreaua1598082005-12-17 13:08:06 +01003462 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01003463
willy tarreau8a86dbf2005-12-18 00:45:59 +01003464 if (s->cli_addr.ss_family == AF_INET)
3465 inet_ntop(AF_INET,
3466 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3467 pn, sizeof(pn));
3468 else
3469 inet_ntop(AF_INET6,
3470 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3471 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01003472
willy tarreauc1cae632005-12-17 14:12:23 +01003473 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01003474 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01003475 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01003476
willy tarreauc1cae632005-12-17 14:12:23 +01003477 tm = localtime(&s->logs.tv_accept.tv_sec);
3478 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01003479 char tmpline[MAX_SYSLOG_LEN], *h;
3480 int hdr;
3481
3482 h = tmpline;
3483 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
3484 *(h++) = ' ';
3485 *(h++) = '{';
3486 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
3487 if (hdr)
3488 *(h++) = '|';
3489 if (s->req_cap[hdr] != NULL)
3490 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
3491 }
3492 *(h++) = '}';
3493 }
3494
3495 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
3496 *(h++) = ' ';
3497 *(h++) = '{';
3498 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
3499 if (hdr)
3500 *(h++) = '|';
3501 if (s->rsp_cap[hdr] != NULL)
3502 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
3503 }
3504 *(h++) = '}';
3505 }
3506
3507 if (h < tmpline + sizeof(tmpline) - 4) {
3508 *(h++) = ' ';
3509 *(h++) = '"';
3510 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
3511 *(h++) = '"';
3512 }
3513 *h = '\0';
3514
willy tarreau5e69b162006-05-12 19:49:37 +02003515 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 +01003516 pn,
3517 (s->cli_addr.ss_family == AF_INET) ?
3518 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3519 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01003520 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3521 tm->tm_hour, tm->tm_min, tm->tm_sec,
3522 pxid, srv,
3523 s->logs.t_request,
willy tarreauf32f5242006-05-02 22:54:52 +02003524 (s->logs.t_queue >= 0) ? s->logs.t_queue - s->logs.t_request : -1,
3525 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreaua1598082005-12-17 13:08:06 +01003526 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003527 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3528 s->logs.status,
3529 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01003530 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
3531 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01003532 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
3533 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
3534 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
3535 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau5e69b162006-05-12 19:49:37 +02003536 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3537 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01003538 }
3539 else {
willy tarreau5f15c552006-05-13 18:37:04 +02003540 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 +01003541 pn,
3542 (s->cli_addr.ss_family == AF_INET) ?
3543 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3544 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01003545 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3546 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01003547 pxid, srv,
willy tarreau5f15c552006-05-13 18:37:04 +02003548 (s->logs.t_queue >= 0) ? s->logs.t_queue : -1,
3549 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003550 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3551 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01003552 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01003553 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreau5e69b162006-05-12 19:49:37 +02003554 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3555 s->logs.srv_queue_size, s->logs.prx_queue_size);
willy tarreaua1598082005-12-17 13:08:06 +01003556 }
3557
3558 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003559}
3560
willy tarreaue39cd132005-12-17 13:00:18 +01003561
3562/*
willy tarreau0f7af912005-12-17 12:21:26 +01003563 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01003564 * to an accept. It tries to accept as many connections as possible.
3565 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01003566 */
3567int event_accept(int fd) {
3568 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003569 struct session *s;
3570 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01003571 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01003572 int max_accept;
3573
3574 if (global.nbproc > 1)
3575 max_accept = 8; /* let other processes catch some connections too */
3576 else
3577 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003578
willy tarreauc2becdc2006-03-19 19:36:48 +01003579 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003580 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003581 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01003582
willy tarreaub1285d52005-12-18 01:20:14 +01003583 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
3584 switch (errno) {
3585 case EAGAIN:
3586 case EINTR:
3587 case ECONNABORTED:
3588 return 0; /* nothing more to accept */
3589 case ENFILE:
3590 send_log(p, LOG_EMERG,
3591 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
3592 p->id, maxfd);
3593 return 0;
3594 case EMFILE:
3595 send_log(p, LOG_EMERG,
3596 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
3597 p->id, maxfd);
3598 return 0;
3599 case ENOBUFS:
3600 case ENOMEM:
3601 send_log(p, LOG_EMERG,
3602 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
3603 p->id, maxfd);
3604 return 0;
3605 default:
3606 return 0;
3607 }
3608 }
willy tarreau0f7af912005-12-17 12:21:26 +01003609
willy tarreau5cbea6f2005-12-17 12:48:26 +01003610 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
3611 Alert("out of memory in event_accept().\n");
3612 FD_CLR(fd, StaticReadEvent);
3613 p->state = PR_STIDLE;
3614 close(cfd);
3615 return 0;
3616 }
willy tarreau0f7af912005-12-17 12:21:26 +01003617
willy tarreaub1285d52005-12-18 01:20:14 +01003618 /* if this session comes from a known monitoring system, we want to ignore
3619 * it as soon as possible, which means closing it immediately for TCP.
3620 */
3621 s->flags = 0;
3622 if (addr.ss_family == AF_INET &&
3623 p->mon_mask.s_addr &&
3624 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
3625 if (p->mode == PR_MODE_TCP) {
3626 close(cfd);
3627 pool_free(session, s);
3628 continue;
3629 }
3630 s->flags |= SN_MONITOR;
3631 }
3632
willy tarreau5cbea6f2005-12-17 12:48:26 +01003633 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3634 Alert("out of memory in event_accept().\n");
3635 FD_CLR(fd, StaticReadEvent);
3636 p->state = PR_STIDLE;
3637 close(cfd);
3638 pool_free(session, s);
3639 return 0;
3640 }
willy tarreau0f7af912005-12-17 12:21:26 +01003641
willy tarreau5cbea6f2005-12-17 12:48:26 +01003642 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01003643 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003644 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
3645 close(cfd);
3646 pool_free(task, t);
3647 pool_free(session, s);
3648 return 0;
3649 }
willy tarreau0f7af912005-12-17 12:21:26 +01003650
willy tarreau5cbea6f2005-12-17 12:48:26 +01003651 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
3652 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
3653 (char *) &one, sizeof(one)) == -1)) {
3654 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
3655 close(cfd);
3656 pool_free(task, t);
3657 pool_free(session, s);
3658 return 0;
3659 }
willy tarreau0f7af912005-12-17 12:21:26 +01003660
willy tarreaub952e1d2005-12-18 01:31:20 +01003661 if (p->options & PR_O_TCP_CLI_KA)
3662 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
3663
willy tarreau9fe663a2005-12-17 13:02:59 +01003664 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02003665 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
willy tarreau9fe663a2005-12-17 13:02:59 +01003666 t->state = TASK_IDLE;
3667 t->process = process_session;
3668 t->context = s;
3669
3670 s->task = t;
3671 s->proxy = p;
3672 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
3673 s->srv_state = SV_STIDLE;
3674 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01003675
willy tarreau9fe663a2005-12-17 13:02:59 +01003676 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
3677 s->cli_fd = cfd;
3678 s->srv_fd = -1;
willy tarreau9e138862006-05-14 23:06:28 +02003679 s->req_line.len = -1;
3680 s->auth_hdr.len = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003681 s->srv = NULL;
Willy TARREAU1a71cc12006-05-14 09:10:03 +02003682 s->pend_pos = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01003683 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01003684
willy tarreaub1285d52005-12-18 01:20:14 +01003685 if (s->flags & SN_MONITOR)
3686 s->logs.logwait = 0;
3687 else
3688 s->logs.logwait = p->to_log;
3689
willy tarreaua1598082005-12-17 13:08:06 +01003690 s->logs.tv_accept = now;
3691 s->logs.t_request = -1;
willy tarreauf32f5242006-05-02 22:54:52 +02003692 s->logs.t_queue = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003693 s->logs.t_connect = -1;
3694 s->logs.t_data = -1;
3695 s->logs.t_close = 0;
3696 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01003697 s->logs.cli_cookie = NULL;
3698 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01003699 s->logs.status = -1;
3700 s->logs.bytes = 0;
willy tarreau5e69b162006-05-12 19:49:37 +02003701 s->logs.prx_queue_size = 0; /* we get the number of pending conns before us */
3702 s->logs.srv_queue_size = 0; /* we will get this number soon */
willy tarreau9fe663a2005-12-17 13:02:59 +01003703
willy tarreaue0331262006-05-15 03:02:46 +02003704 s->data_source = DATA_SRC_NONE;
willy tarreaue0331262006-05-15 03:02:46 +02003705
willy tarreau2f6ba652005-12-17 13:57:42 +01003706 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02003707 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01003708
willy tarreau4302f492005-12-18 01:00:37 +01003709 if (p->nb_req_cap > 0) {
3710 if ((s->req_cap =
3711 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
3712 == NULL) { /* no memory */
3713 close(cfd); /* nothing can be done for this fd without memory */
3714 pool_free(task, t);
3715 pool_free(session, s);
3716 return 0;
3717 }
3718 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
3719 }
3720 else
3721 s->req_cap = NULL;
3722
3723 if (p->nb_rsp_cap > 0) {
3724 if ((s->rsp_cap =
3725 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
3726 == NULL) { /* no memory */
3727 if (s->req_cap != NULL)
3728 pool_free_to(p->req_cap_pool, s->req_cap);
3729 close(cfd); /* nothing can be done for this fd without memory */
3730 pool_free(task, t);
3731 pool_free(session, s);
3732 return 0;
3733 }
3734 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
3735 }
3736 else
3737 s->rsp_cap = NULL;
3738
willy tarreau5cbea6f2005-12-17 12:48:26 +01003739 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
3740 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003741 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003742 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01003743
willy tarreau8a86dbf2005-12-18 00:45:59 +01003744 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003745 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003746 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003747 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01003748
willy tarreau9fe663a2005-12-17 13:02:59 +01003749 if (p->to_log) {
3750 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01003751 if (s->logs.logwait & LW_CLIP)
3752 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01003753 sess_log(s);
3754 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01003755 else if (s->cli_addr.ss_family == AF_INET) {
3756 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
3757 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
3758 sn, sizeof(sn)) &&
3759 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3760 pn, sizeof(pn))) {
3761 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3762 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
3763 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
3764 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3765 }
3766 }
3767 else {
3768 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
3769 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
3770 sn, sizeof(sn)) &&
3771 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
3772 pn, sizeof(pn))) {
3773 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3774 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
3775 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
3776 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3777 }
3778 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003779 }
willy tarreau0f7af912005-12-17 12:21:26 +01003780
willy tarreau982249e2005-12-18 00:57:06 +01003781 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01003782 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003783 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01003784 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01003785 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003786 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003787 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01003788 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01003789
willy tarreau8a86dbf2005-12-18 00:45:59 +01003790 if (s->cli_addr.ss_family == AF_INET) {
3791 char pn[INET_ADDRSTRLEN];
3792 inet_ntop(AF_INET,
3793 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3794 pn, sizeof(pn));
3795
3796 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3797 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3798 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
3799 }
3800 else {
3801 char pn[INET6_ADDRSTRLEN];
3802 inet_ntop(AF_INET6,
3803 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3804 pn, sizeof(pn));
3805
3806 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3807 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3808 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3809 }
3810
willy tarreauef900ab2005-12-17 12:52:52 +01003811 write(1, trash, len);
3812 }
willy tarreau0f7af912005-12-17 12:21:26 +01003813
willy tarreau5cbea6f2005-12-17 12:48:26 +01003814 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003815 if (s->rsp_cap != NULL)
3816 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3817 if (s->req_cap != NULL)
3818 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003819 close(cfd); /* nothing can be done for this fd without memory */
3820 pool_free(task, t);
3821 pool_free(session, s);
3822 return 0;
3823 }
willy tarreau4302f492005-12-18 01:00:37 +01003824
willy tarreau5cbea6f2005-12-17 12:48:26 +01003825 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003826 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003827 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3828 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003829 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003830 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003831
willy tarreau5cbea6f2005-12-17 12:48:26 +01003832 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3833 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003834 if (s->rsp_cap != NULL)
3835 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3836 if (s->req_cap != NULL)
3837 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003838 close(cfd); /* nothing can be done for this fd without memory */
3839 pool_free(task, t);
3840 pool_free(session, s);
3841 return 0;
3842 }
3843 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003844 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003845 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 +01003846
willy tarreau5cbea6f2005-12-17 12:48:26 +01003847 fdtab[cfd].read = &event_cli_read;
3848 fdtab[cfd].write = &event_cli_write;
3849 fdtab[cfd].owner = t;
3850 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003851
willy tarreaub1285d52005-12-18 01:20:14 +01003852 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3853 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3854 /* Either we got a request from a monitoring system on an HTTP instance,
3855 * or we're in health check mode with the 'httpchk' option enabled. In
3856 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3857 */
3858 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3859 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3860 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003861 }
3862 else {
3863 FD_SET(cfd, StaticReadEvent);
3864 }
3865
willy tarreaub952e1d2005-12-18 01:31:20 +01003866#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3867 if (PrevReadEvent) {
3868 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3869 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3870 }
3871#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003872 fd_insert(cfd);
3873
3874 tv_eternity(&s->cnexpire);
3875 tv_eternity(&s->srexpire);
3876 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003877 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003878 tv_eternity(&s->cwexpire);
3879
willy tarreaub1285d52005-12-18 01:20:14 +01003880 if (s->proxy->clitimeout) {
3881 if (FD_ISSET(cfd, StaticReadEvent))
3882 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3883 if (FD_ISSET(cfd, StaticWriteEvent))
3884 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3885 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003886
willy tarreaub1285d52005-12-18 01:20:14 +01003887 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003888
3889 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003890
3891 if (p->mode != PR_MODE_HEALTH)
3892 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003893
3894 p->nbconn++;
willy tarreaucb406512006-05-18 00:52:35 +02003895 if (p->nbconn > p->nbconn_max)
3896 p->nbconn_max = p->nbconn;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003897 actconn++;
3898 totalconn++;
3899
willy tarreaub952e1d2005-12-18 01:31:20 +01003900 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003901 } /* end of while (p->nbconn < p->maxconn) */
3902 return 0;
3903}
willy tarreau0f7af912005-12-17 12:21:26 +01003904
willy tarreau0f7af912005-12-17 12:21:26 +01003905
willy tarreau5cbea6f2005-12-17 12:48:26 +01003906/*
3907 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003908 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3909 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003910 * or -1 if an error occured.
3911 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003912int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003913 struct task *t = fdtab[fd].owner;
3914 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003915 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003916 socklen_t lskerr = sizeof(skerr);
3917
willy tarreau05be12b2006-03-19 19:35:00 +01003918 skerr = 1;
3919 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3920 || (skerr != 0)) {
3921 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003922 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003923 fdtab[fd].state = FD_STERROR;
3924 FD_CLR(fd, StaticWriteEvent);
3925 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003926 else if (s->result != -1) {
3927 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003928 if (s->proxy->options & PR_O_HTTP_CHK) {
3929 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003930 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003931 * so we'll send the request, and won't wake the checker up now.
3932 */
3933#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003934 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003935#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003936 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003937#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003938 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003939 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3940 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3941 return 0;
3942 }
willy tarreau05be12b2006-03-19 19:35:00 +01003943 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003944 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003945 FD_CLR(fd, StaticWriteEvent);
3946 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003947 }
3948 else {
3949 /* good TCP connection is enough */
3950 s->result = 1;
3951 }
3952 }
3953
3954 task_wakeup(&rq, t);
3955 return 0;
3956}
3957
willy tarreau0f7af912005-12-17 12:21:26 +01003958
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003959/*
3960 * This function is used only for server health-checks. It handles
3961 * the server's reply to an HTTP request. It returns 1 if the server replies
3962 * 2xx or 3xx (valid responses), or -1 in other cases.
3963 */
3964int event_srv_chk_r(int fd) {
3965 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003966 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003967 struct task *t = fdtab[fd].owner;
3968 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003969 int skerr;
3970 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003971
willy tarreaua4a583a2005-12-18 01:39:19 +01003972 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003973
willy tarreau05be12b2006-03-19 19:35:00 +01003974 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3975 if (!skerr) {
3976#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003977 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003978#else
willy tarreau05be12b2006-03-19 19:35:00 +01003979 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3980 * but the connection was closed on the remote end. Fortunately, recv still
3981 * works correctly and we don't need to do the getsockopt() on linux.
3982 */
3983 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003984#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003985
3986 if ((len >= sizeof("HTTP/1.0 000")) &&
3987 !memcmp(reply, "HTTP/1.", 7) &&
3988 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3989 result = 1;
3990 }
3991
3992 if (result == -1)
3993 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003994
3995 if (s->result != -1)
3996 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003997
3998 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003999 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01004000 return 0;
4001}
4002
4003
4004/*
4005 * this function writes the string <str> at position <pos> which must be in buffer <b>,
4006 * and moves <end> just after the end of <str>.
4007 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
4008 * the shift value (positive or negative) is returned.
4009 * If there's no space left, the move is not done.
4010 *
4011 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004012int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01004013 int delta;
4014 int len;
4015
4016 len = strlen(str);
4017 delta = len - (end - pos);
4018
4019 if (delta + b->r >= b->data + BUFSIZE)
4020 return 0; /* no space left */
4021
4022 /* first, protect the end of the buffer */
4023 memmove(end + delta, end, b->data + b->l - end);
4024
4025 /* now, copy str over pos */
4026 memcpy(pos, str,len);
4027
willy tarreau5cbea6f2005-12-17 12:48:26 +01004028 /* we only move data after the displaced zone */
4029 if (b->r > pos) b->r += delta;
4030 if (b->w > pos) b->w += delta;
4031 if (b->h > pos) b->h += delta;
4032 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01004033 b->l += delta;
4034
4035 return delta;
4036}
4037
willy tarreau8337c6b2005-12-17 13:41:01 +01004038/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01004039 * len is 0.
4040 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004041int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01004042 int delta;
4043
4044 delta = len - (end - pos);
4045
4046 if (delta + b->r >= b->data + BUFSIZE)
4047 return 0; /* no space left */
4048
Willy TARREAUe78ae262006-01-08 01:24:12 +01004049 if (b->data + b->l < end)
4050 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
4051 return 0;
4052
willy tarreau0f7af912005-12-17 12:21:26 +01004053 /* first, protect the end of the buffer */
4054 memmove(end + delta, end, b->data + b->l - end);
4055
4056 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01004057 if (len)
4058 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01004059
willy tarreau5cbea6f2005-12-17 12:48:26 +01004060 /* we only move data after the displaced zone */
4061 if (b->r > pos) b->r += delta;
4062 if (b->w > pos) b->w += delta;
4063 if (b->h > pos) b->h += delta;
4064 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01004065 b->l += delta;
4066
4067 return delta;
4068}
4069
4070
4071int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
4072 char *old_dst = dst;
4073
4074 while (*str) {
4075 if (*str == '\\') {
4076 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01004077 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004078 int len, num;
4079
4080 num = *str - '0';
4081 str++;
4082
willy tarreau8a86dbf2005-12-18 00:45:59 +01004083 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01004084 len = matches[num].rm_eo - matches[num].rm_so;
4085 memcpy(dst, src + matches[num].rm_so, len);
4086 dst += len;
4087 }
4088
4089 }
4090 else if (*str == 'x') {
4091 unsigned char hex1, hex2;
4092 str++;
4093
willy tarreauc1f47532005-12-18 01:08:26 +01004094 hex1 = toupper(*str++) - '0';
4095 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01004096
4097 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
4098 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
4099 *dst++ = (hex1<<4) + hex2;
4100 }
4101 else
4102 *dst++ = *str++;
4103 }
4104 else
4105 *dst++ = *str++;
4106 }
4107 *dst = 0;
4108 return dst - old_dst;
4109}
4110
willy tarreauc1f47532005-12-18 01:08:26 +01004111static int ishex(char s)
4112{
4113 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
4114}
4115
4116/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
4117char *check_replace_string(char *str)
4118{
4119 char *err = NULL;
4120 while (*str) {
4121 if (*str == '\\') {
4122 err = str; /* in case of a backslash, we return the pointer to it */
4123 str++;
4124 if (!*str)
4125 return err;
4126 else if (isdigit((int)*str))
4127 err = NULL;
4128 else if (*str == 'x') {
4129 str++;
4130 if (!ishex(*str))
4131 return err;
4132 str++;
4133 if (!ishex(*str))
4134 return err;
4135 err = NULL;
4136 }
4137 else {
4138 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
4139 err = NULL;
4140 }
4141 }
4142 str++;
4143 }
4144 return err;
4145}
4146
willy tarreau0f7af912005-12-17 12:21:26 +01004147/*
4148 * manages the client FSM and its socket. BTW, it also tries to handle the
4149 * cookie. It returns 1 if a state has changed (and a resync may be needed),
4150 * 0 else.
4151 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004152int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004153 int s = t->srv_state;
4154 int c = t->cli_state;
4155 struct buffer *req = t->req;
4156 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004157 int method_checked = 0;
4158 appsess *asession_temp = NULL;
4159 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01004160
willy tarreau750a4722005-12-17 13:21:24 +01004161#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01004162 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
4163 cli_stnames[c], srv_stnames[s],
4164 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4165 t->crexpire.tv_sec, t->crexpire.tv_usec,
4166 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01004167#endif
willy tarreau0f7af912005-12-17 12:21:26 +01004168 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4169 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4170 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4171 //);
4172 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004173 /* now parse the partial (or complete) headers */
4174 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
4175 char *ptr;
4176 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01004177 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01004178
willy tarreau5cbea6f2005-12-17 12:48:26 +01004179 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01004180
willy tarreau0f7af912005-12-17 12:21:26 +01004181 /* look for the end of the current header */
4182 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
4183 ptr++;
4184
willy tarreau5cbea6f2005-12-17 12:48:26 +01004185 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004186 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02004187
4188 /*
4189 * first, let's check that it's not a leading empty line, in
4190 * which case we'll ignore and remove it (according to RFC2616).
4191 */
4192 if (req->h == req->data) {
4193 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4194 if (ptr > req->r - 2) {
4195 /* this is a partial header, let's wait for more to come */
4196 req->lr = ptr;
4197 break;
4198 }
4199
4200 /* now we know that *ptr is either \r or \n,
4201 * and that there are at least 1 char after it.
4202 */
4203 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4204 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4205 else
4206 req->lr = ptr + 2; /* \r\n or \n\r */
4207 /* ignore empty leading lines */
4208 buffer_replace2(req, req->h, req->lr, NULL, 0);
4209 req->h = req->lr;
4210 continue;
4211 }
4212
willy tarreau5cbea6f2005-12-17 12:48:26 +01004213 /* we can only get here after an end of headers */
4214 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01004215
willy tarreaue39cd132005-12-17 13:00:18 +01004216 if (t->flags & SN_CLDENY) {
4217 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01004218 t->logs.status = 403;
willy tarreau47ee7ad2006-05-18 01:25:36 +02004219 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now); /* let's log the request time */
willy tarreau8337c6b2005-12-17 13:41:01 +01004220 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01004221 if (!(t->flags & SN_ERR_MASK))
4222 t->flags |= SN_ERR_PRXCOND;
4223 if (!(t->flags & SN_FINST_MASK))
4224 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004225 return 1;
4226 }
4227
willy tarreau9e138862006-05-14 23:06:28 +02004228 /* Right now, we know that we have processed the entire headers
4229 * and that unwanted requests have been filtered out. We can do
4230 * whatever we want.
4231 */
4232
willy tarreau9e138862006-05-14 23:06:28 +02004233 if (t->proxy->uri_auth != NULL
4234 && t->req_line.len >= t->proxy->uri_auth->uri_len + 4) { /* +4 for "GET /" */
4235 if (!memcmp(t->req_line.str + 4,
4236 t->proxy->uri_auth->uri_prefix, t->proxy->uri_auth->uri_len)
4237 && !memcmp(t->req_line.str, "GET ", 4)) {
4238 struct user_auth *user;
4239 int authenticated;
4240
4241 /* we are in front of a interceptable URI. Let's check
4242 * if there's an authentication and if it's valid.
4243 */
4244 user = t->proxy->uri_auth->users;
4245 if (!user) {
4246 /* no user auth required, it's OK */
4247 authenticated = 1;
4248 } else {
4249 authenticated = 0;
4250
4251 /* a user list is defined, we have to check.
4252 * skip 21 chars for "Authorization: Basic ".
4253 */
4254 if (t->auth_hdr.len < 21 || memcmp(t->auth_hdr.str + 14, " Basic ", 7))
4255 user = NULL;
4256
4257 while (user) {
4258 if ((t->auth_hdr.len == user->user_len + 21)
4259 && !memcmp(t->auth_hdr.str+21, user->user_pwd, user->user_len)) {
4260 authenticated = 1;
4261 break;
4262 }
4263 user = user->next;
willy tarreau9e138862006-05-14 23:06:28 +02004264 }
4265 }
4266
4267 if (!authenticated) {
4268 int msglen;
4269
4270 /* no need to go further */
4271
4272 msglen = sprintf(trash, HTTP_401_fmt, t->proxy->uri_auth->auth_realm);
4273 t->logs.status = 401;
4274 client_retnclose(t, msglen, trash);
4275 if (!(t->flags & SN_ERR_MASK))
4276 t->flags |= SN_ERR_PRXCOND;
4277 if (!(t->flags & SN_FINST_MASK))
4278 t->flags |= SN_FINST_R;
4279 return 1;
4280 }
4281
willy tarreaue0331262006-05-15 03:02:46 +02004282 t->cli_state = CL_STSHUTR;
willy tarreau950609c2006-05-18 01:23:51 +02004283 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
4284 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreaue0331262006-05-15 03:02:46 +02004285 t->data_source = DATA_SRC_STATS;
willy tarreau1f431b52006-05-21 14:46:15 +02004286 t->data_state = DATA_ST_INIT;
willy tarreaue0331262006-05-15 03:02:46 +02004287 produce_content(t);
4288 return 1;
willy tarreau9e138862006-05-14 23:06:28 +02004289 }
4290 }
4291
4292
willy tarreau5cbea6f2005-12-17 12:48:26 +01004293 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004294 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
4295 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004296 }
willy tarreau0f7af912005-12-17 12:21:26 +01004297
willy tarreau9fe663a2005-12-17 13:02:59 +01004298 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01004299 if (t->cli_addr.ss_family == AF_INET) {
4300 unsigned char *pn;
4301 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
4302 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
4303 pn[0], pn[1], pn[2], pn[3]);
4304 buffer_replace2(req, req->h, req->h, trash, len);
4305 }
4306 else if (t->cli_addr.ss_family == AF_INET6) {
4307 char pn[INET6_ADDRSTRLEN];
4308 inet_ntop(AF_INET6,
4309 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
4310 pn, sizeof(pn));
4311 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
4312 buffer_replace2(req, req->h, req->h, trash, len);
4313 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004314 }
4315
willy tarreau25c4ea52005-12-18 00:49:49 +01004316 /* add a "connection: close" line if needed */
4317 if (t->proxy->options & PR_O_HTTP_CLOSE)
4318 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
4319
willy tarreau982249e2005-12-18 00:57:06 +01004320 if (!memcmp(req->data, "POST ", 5)) {
4321 /* this is a POST request, which is not cacheable by default */
4322 t->flags |= SN_POST;
4323 }
willy tarreaucd878942005-12-17 13:27:43 +01004324
willy tarreau5cbea6f2005-12-17 12:48:26 +01004325 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004326 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01004327
willy tarreau750a4722005-12-17 13:21:24 +01004328 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004329 /* FIXME: we'll set the client in a wait state while we try to
4330 * connect to the server. Is this really needed ? wouldn't it be
willy tarreau0889c962006-04-24 14:36:48 +02004331 * better to release the maximum of system buffers instead ?
4332 * The solution is to enable the FD but set its time-out to
4333 * eternity as long as the server-side does not enable data xfer.
4334 * CL_STDATA also has to take care of this, which is done below.
4335 */
willy tarreauef900ab2005-12-17 12:52:52 +01004336 //FD_CLR(t->cli_fd, StaticReadEvent);
4337 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01004338
4339 /* FIXME: if we break here (as up to 1.1.23), having the client
4340 * shutdown its connection can lead to an abort further.
4341 * it's better to either return 1 or even jump directly to the
4342 * data state which will save one schedule.
4343 */
4344 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01004345
4346 if (!t->proxy->clitimeout ||
4347 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4348 /* If the client has no timeout, or if the server is not ready yet,
4349 * and we know for sure that it can expire, then it's cleaner to
4350 * disable the timeout on the client side so that too low values
4351 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01004352 *
4353 * FIXME-20050705: the server needs a way to re-enable this time-out
4354 * when it switches its state, otherwise a client can stay connected
4355 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01004356 */
4357 tv_eternity(&t->crexpire);
4358
willy tarreau197e8ec2005-12-17 14:10:59 +01004359 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004360 }
willy tarreau0f7af912005-12-17 12:21:26 +01004361
Willy TARREAU13032e72006-03-12 17:31:45 +01004362 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4363 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004364 /* this is a partial header, let's wait for more to come */
4365 req->lr = ptr;
4366 break;
4367 }
willy tarreau0f7af912005-12-17 12:21:26 +01004368
willy tarreau5cbea6f2005-12-17 12:48:26 +01004369 /* now we know that *ptr is either \r or \n,
4370 * and that there are at least 1 char after it.
4371 */
4372 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4373 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4374 else
4375 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01004376
willy tarreau5cbea6f2005-12-17 12:48:26 +01004377 /*
4378 * now we know that we have a full header ; we can do whatever
4379 * we want with these pointers :
4380 * req->h = beginning of header
4381 * ptr = end of header (first \r or \n)
4382 * req->lr = beginning of next line (next rep->h)
4383 * req->r = end of data (not used at this stage)
4384 */
willy tarreau0f7af912005-12-17 12:21:26 +01004385
willy tarreau12350152005-12-18 01:03:27 +01004386 if (!method_checked && (t->proxy->appsession_name != NULL) &&
4387 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
4388 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
4389
4390 /* skip ; */
4391 request_line++;
4392
4393 /* look if we have a jsessionid */
4394
4395 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
4396
4397 /* skip jsessionid= */
4398 request_line += t->proxy->appsession_name_len + 1;
4399
4400 /* First try if we allready have an appsession */
4401 asession_temp = &local_asession;
4402
4403 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4404 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
4405 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
4406 return 0;
4407 }
4408
4409 /* Copy the sessionid */
4410 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
4411 asession_temp->sessid[t->proxy->appsession_len] = 0;
4412 asession_temp->serverid = NULL;
4413
4414 /* only do insert, if lookup fails */
4415 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
4416 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4417 Alert("Not enough memory process_cli():asession:calloc().\n");
4418 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4419 return 0;
4420 }
4421 asession_temp->sessid = local_asession.sessid;
4422 asession_temp->serverid = local_asession.serverid;
4423 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004424 } /* end if (chtbl_lookup()) */
4425 else {
willy tarreau12350152005-12-18 01:03:27 +01004426 /*free wasted memory;*/
4427 pool_free_to(apools.sessid, local_asession.sessid);
4428 }
4429
4430 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4431 asession_temp->request_count++;
4432
4433#if defined(DEBUG_HASH)
4434 print_table(&(t->proxy->htbl_proxy));
4435#endif
4436
4437 if (asession_temp->serverid == NULL) {
4438 Alert("Found Application Session without matching server.\n");
4439 } else {
4440 struct server *srv = t->proxy->srv;
4441 while (srv) {
4442 if (strcmp(srv->id, asession_temp->serverid) == 0) {
4443 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4444 /* we found the server and it's usable */
4445 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004446 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004447 t->srv = srv;
4448 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01004449 } else {
willy tarreau12350152005-12-18 01:03:27 +01004450 t->flags &= ~SN_CK_MASK;
4451 t->flags |= SN_CK_DOWN;
4452 }
willy tarreaub952e1d2005-12-18 01:31:20 +01004453 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01004454 srv = srv->next;
4455 }/* end while(srv) */
4456 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01004457 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01004458 else {
4459 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
4460 }
willy tarreau598da412005-12-18 01:07:29 +01004461 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01004462 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01004463 else{
4464 //printf("No Methode-Header with Session-String\n");
4465 }
4466
willy tarreau8337c6b2005-12-17 13:41:01 +01004467 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004468 /* we have a complete HTTP request that we must log */
4469 int urilen;
4470
willy tarreaua1598082005-12-17 13:08:06 +01004471 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004472 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01004473 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01004474 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01004475 if (!(t->flags & SN_ERR_MASK))
4476 t->flags |= SN_ERR_PRXCOND;
4477 if (!(t->flags & SN_FINST_MASK))
4478 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01004479 return 1;
4480 }
4481
4482 urilen = ptr - req->h;
4483 if (urilen >= REQURI_LEN)
4484 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01004485 memcpy(t->logs.uri, req->h, urilen);
4486 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004487
willy tarreaua1598082005-12-17 13:08:06 +01004488 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01004489 sess_log(t);
4490 }
willy tarreau4302f492005-12-18 01:00:37 +01004491 else if (t->logs.logwait & LW_REQHDR) {
4492 struct cap_hdr *h;
4493 int len;
4494 for (h = t->proxy->req_cap; h; h = h->next) {
4495 if ((h->namelen + 2 <= ptr - req->h) &&
4496 (req->h[h->namelen] == ':') &&
4497 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
4498
4499 if (t->req_cap[h->index] == NULL)
4500 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4501
4502 len = ptr - (req->h + h->namelen + 2);
4503 if (len > h->len)
4504 len = h->len;
4505
4506 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
4507 t->req_cap[h->index][len]=0;
4508 }
4509 }
4510
4511 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004512
willy tarreau5cbea6f2005-12-17 12:48:26 +01004513 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004514
willy tarreau982249e2005-12-18 00:57:06 +01004515 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004516 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004517 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 +01004518 max = ptr - req->h;
4519 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004520 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004521 trash[len++] = '\n';
4522 write(1, trash, len);
4523 }
willy tarreau0f7af912005-12-17 12:21:26 +01004524
willy tarreau25c4ea52005-12-18 00:49:49 +01004525
4526 /* remove "connection: " if needed */
4527 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4528 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
4529 delete_header = 1;
4530 }
4531
willy tarreau5cbea6f2005-12-17 12:48:26 +01004532 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004533 if (!delete_header && t->proxy->req_exp != NULL
4534 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004535 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004536 char term;
4537
4538 term = *ptr;
4539 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004540 exp = t->proxy->req_exp;
4541 do {
4542 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
4543 switch (exp->action) {
4544 case ACT_ALLOW:
4545 if (!(t->flags & SN_CLDENY))
4546 t->flags |= SN_CLALLOW;
4547 break;
4548 case ACT_REPLACE:
4549 if (!(t->flags & SN_CLDENY)) {
4550 int len = exp_replace(trash, req->h, exp->replace, pmatch);
4551 ptr += buffer_replace2(req, req->h, ptr, trash, len);
4552 }
4553 break;
4554 case ACT_REMOVE:
4555 if (!(t->flags & SN_CLDENY))
4556 delete_header = 1;
4557 break;
4558 case ACT_DENY:
4559 if (!(t->flags & SN_CLALLOW))
4560 t->flags |= SN_CLDENY;
4561 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004562 case ACT_PASS: /* we simply don't deny this one */
4563 break;
willy tarreau0f7af912005-12-17 12:21:26 +01004564 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004565 break;
willy tarreau0f7af912005-12-17 12:21:26 +01004566 }
willy tarreaue39cd132005-12-17 13:00:18 +01004567 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004568 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01004569 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004570
willy tarreau240afa62005-12-17 13:14:35 +01004571 /* Now look for cookies. Conforming to RFC2109, we have to support
4572 * attributes whose name begin with a '$', and associate them with
4573 * the right cookie, if we want to delete this cookie.
4574 * So there are 3 cases for each cookie read :
4575 * 1) it's a special attribute, beginning with a '$' : ignore it.
4576 * 2) it's a server id cookie that we *MAY* want to delete : save
4577 * some pointers on it (last semi-colon, beginning of cookie...)
4578 * 3) it's an application cookie : we *MAY* have to delete a previous
4579 * "special" cookie.
4580 * At the end of loop, if a "special" cookie remains, we may have to
4581 * remove it. If no application cookie persists in the header, we
4582 * *MUST* delete it
4583 */
willy tarreau12350152005-12-18 01:03:27 +01004584 if (!delete_header &&
4585 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01004586 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01004587 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004588 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01004589 char *del_colon, *del_cookie, *colon;
4590 int app_cookies;
4591
willy tarreau5cbea6f2005-12-17 12:48:26 +01004592 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01004593 colon = p1;
4594 /* del_cookie == NULL => nothing to be deleted */
4595 del_colon = del_cookie = NULL;
4596 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004597
4598 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01004599 /* skip spaces and colons, but keep an eye on these ones */
4600 while (p1 < ptr) {
4601 if (*p1 == ';' || *p1 == ',')
4602 colon = p1;
4603 else if (!isspace((int)*p1))
4604 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004605 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01004606 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004607
4608 if (p1 == ptr)
4609 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004610
4611 /* p1 is at the beginning of the cookie name */
4612 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01004613 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004614 p2++;
4615
4616 if (p2 == ptr)
4617 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004618
4619 p3 = p2 + 1; /* skips the '=' sign */
4620 if (p3 == ptr)
4621 break;
4622
willy tarreau240afa62005-12-17 13:14:35 +01004623 p4 = p3;
4624 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004625 p4++;
4626
4627 /* here, we have the cookie name between p1 and p2,
4628 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01004629 * we can process it :
4630 *
4631 * Cookie: NAME=VALUE;
4632 * | || || |
4633 * | || || +--> p4
4634 * | || |+-------> p3
4635 * | || +--------> p2
4636 * | |+------------> p1
4637 * | +-------------> colon
4638 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01004639 */
4640
willy tarreau240afa62005-12-17 13:14:35 +01004641 if (*p1 == '$') {
4642 /* skip this one */
4643 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004644 else {
4645 /* first, let's see if we want to capture it */
4646 if (t->proxy->capture_name != NULL &&
4647 t->logs.cli_cookie == NULL &&
4648 (p4 - p1 >= t->proxy->capture_namelen) &&
4649 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4650 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004651
willy tarreau8337c6b2005-12-17 13:41:01 +01004652 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4653 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01004654 } else {
4655 if (log_len > t->proxy->capture_len)
4656 log_len = t->proxy->capture_len;
4657 memcpy(t->logs.cli_cookie, p1, log_len);
4658 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01004659 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004660 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004661
4662 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4663 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
4664 /* Cool... it's the right one */
4665 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01004666 char *delim;
4667
4668 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4669 * have the server ID betweek p3 and delim, and the original cookie between
4670 * delim+1 and p4. Otherwise, delim==p4 :
4671 *
4672 * Cookie: NAME=SRV~VALUE;
4673 * | || || | |
4674 * | || || | +--> p4
4675 * | || || +--------> delim
4676 * | || |+-----------> p3
4677 * | || +------------> p2
4678 * | |+----------------> p1
4679 * | +-----------------> colon
4680 * +------------------------> req->h
4681 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004682
willy tarreau0174f312005-12-18 01:02:42 +01004683 if (t->proxy->options & PR_O_COOK_PFX) {
4684 for (delim = p3; delim < p4; delim++)
4685 if (*delim == COOKIE_DELIM)
4686 break;
4687 }
4688 else
4689 delim = p4;
4690
4691
4692 /* Here, we'll look for the first running server which supports the cookie.
4693 * This allows to share a same cookie between several servers, for example
4694 * to dedicate backup servers to specific servers only.
willy tarreau422bb2e2006-05-10 04:27:21 +02004695 * However, to prevent clients from sticking to cookie-less backup server
4696 * when they have incidentely learned an empty cookie, we simply ignore
4697 * empty cookies and mark them as invalid.
willy tarreau0174f312005-12-18 01:02:42 +01004698 */
willy tarreau422bb2e2006-05-10 04:27:21 +02004699 if (delim == p3)
4700 srv = NULL;
4701
willy tarreau0174f312005-12-18 01:02:42 +01004702 while (srv) {
4703 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
4704 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4705 /* we found the server and it's usable */
4706 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004707 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau0174f312005-12-18 01:02:42 +01004708 t->srv = srv;
4709 break;
willy tarreau12350152005-12-18 01:03:27 +01004710 } else {
willy tarreau0174f312005-12-18 01:02:42 +01004711 /* we found a server, but it's down */
4712 t->flags &= ~SN_CK_MASK;
4713 t->flags |= SN_CK_DOWN;
4714 }
4715 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004716 srv = srv->next;
4717 }
4718
willy tarreau0174f312005-12-18 01:02:42 +01004719 if (!srv && !(t->flags & SN_CK_DOWN)) {
4720 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01004721 t->flags &= ~SN_CK_MASK;
4722 t->flags |= SN_CK_INVALID;
4723 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004724
willy tarreau0174f312005-12-18 01:02:42 +01004725 /* depending on the cookie mode, we may have to either :
4726 * - delete the complete cookie if we're in insert+indirect mode, so that
4727 * the server never sees it ;
4728 * - remove the server id from the cookie value, and tag the cookie as an
4729 * application cookie so that it does not get accidentely removed later,
4730 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01004731 */
willy tarreau0174f312005-12-18 01:02:42 +01004732 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
4733 buffer_replace2(req, p3, delim + 1, NULL, 0);
4734 p4 -= (delim + 1 - p3);
4735 ptr -= (delim + 1 - p3);
4736 del_cookie = del_colon = NULL;
4737 app_cookies++; /* protect the header from deletion */
4738 }
4739 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01004740 (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 +01004741 del_cookie = p1;
4742 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01004743 }
willy tarreau12350152005-12-18 01:03:27 +01004744 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01004745 /* now we know that we must keep this cookie since it's
4746 * not ours. But if we wanted to delete our cookie
4747 * earlier, we cannot remove the complete header, but we
4748 * can remove the previous block itself.
4749 */
4750 app_cookies++;
4751
4752 if (del_cookie != NULL) {
4753 buffer_replace2(req, del_cookie, p1, NULL, 0);
4754 p4 -= (p1 - del_cookie);
4755 ptr -= (p1 - del_cookie);
4756 del_cookie = del_colon = NULL;
4757 }
willy tarreau240afa62005-12-17 13:14:35 +01004758 }
willy tarreau12350152005-12-18 01:03:27 +01004759
4760 if ((t->proxy->appsession_name != NULL) &&
4761 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4762 /* first, let's see if the cookie is our appcookie*/
4763
4764 /* Cool... it's the right one */
4765
4766 asession_temp = &local_asession;
4767
4768 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4769 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4770 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4771 return 0;
4772 }
4773
4774 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4775 asession_temp->sessid[t->proxy->appsession_len] = 0;
4776 asession_temp->serverid = NULL;
4777
4778 /* only do insert, if lookup fails */
4779 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4780 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4781 Alert("Not enough memory process_cli():asession:calloc().\n");
4782 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4783 return 0;
4784 }
4785
4786 asession_temp->sessid = local_asession.sessid;
4787 asession_temp->serverid = local_asession.serverid;
4788 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4789 }
4790 else{
4791 /* free wasted memory */
4792 pool_free_to(apools.sessid, local_asession.sessid);
4793 }
4794
4795 if (asession_temp->serverid == NULL) {
4796 Alert("Found Application Session without matching server.\n");
4797 } else {
4798 struct server *srv = t->proxy->srv;
4799 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01004800 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01004801 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4802 /* we found the server and it's usable */
4803 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004804 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004805 t->srv = srv;
4806 break;
4807 } else {
4808 t->flags &= ~SN_CK_MASK;
4809 t->flags |= SN_CK_DOWN;
4810 }
4811 }
4812 srv = srv->next;
4813 }/* end while(srv) */
4814 }/* end else if server == NULL */
4815
4816 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01004817 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004818 }
willy tarreau240afa62005-12-17 13:14:35 +01004819
willy tarreau5cbea6f2005-12-17 12:48:26 +01004820 /* we'll have to look for another cookie ... */
4821 p1 = p4;
4822 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01004823
4824 /* There's no more cookie on this line.
4825 * We may have marked the last one(s) for deletion.
4826 * We must do this now in two ways :
4827 * - if there is no app cookie, we simply delete the header ;
4828 * - if there are app cookies, we must delete the end of the
4829 * string properly, including the colon/semi-colon before
4830 * the cookie name.
4831 */
4832 if (del_cookie != NULL) {
4833 if (app_cookies) {
4834 buffer_replace2(req, del_colon, ptr, NULL, 0);
4835 /* WARNING! <ptr> becomes invalid for now. If some code
4836 * below needs to rely on it before the end of the global
4837 * header loop, we need to correct it with this code :
willy tarreau240afa62005-12-17 13:14:35 +01004838 */
willy tarreau9e138862006-05-14 23:06:28 +02004839 ptr = del_colon;
willy tarreau240afa62005-12-17 13:14:35 +01004840 }
4841 else
4842 delete_header = 1;
4843 }
4844 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004845
4846 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004847 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01004848 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau9e138862006-05-14 23:06:28 +02004849 /* WARNING: ptr is not valid anymore, since the header may have
4850 * been deleted or truncated ! */
4851 } else {
4852 /* try to catch the first line as the request */
4853 if (t->req_line.len < 0) {
4854 t->req_line.str = req->h;
4855 t->req_line.len = ptr - req->h;
4856 }
4857
4858 /* We might also need the 'Authorization: ' header */
4859 if (t->auth_hdr.len < 0 &&
4860 t->proxy->uri_auth != NULL &&
4861 ptr > req->h + 15 &&
4862 !strncasecmp("Authorization: ", req->h, 15)) {
4863 t->auth_hdr.str = req->h;
4864 t->auth_hdr.len = ptr - req->h;
4865 }
willy tarreau0f7af912005-12-17 12:21:26 +01004866 }
willy tarreau240afa62005-12-17 13:14:35 +01004867
willy tarreau5cbea6f2005-12-17 12:48:26 +01004868 req->h = req->lr;
4869 } /* while (req->lr < req->r) */
4870
4871 /* end of header processing (even if incomplete) */
4872
willy tarreauef900ab2005-12-17 12:52:52 +01004873 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4874 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4875 * full. We cannot loop here since event_cli_read will disable it only if
4876 * req->l == rlim-data
4877 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004878 FD_SET(t->cli_fd, StaticReadEvent);
4879 if (t->proxy->clitimeout)
4880 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4881 else
4882 tv_eternity(&t->crexpire);
4883 }
4884
willy tarreaue39cd132005-12-17 13:00:18 +01004885 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01004886 * won't be able to free more later, so the session will never terminate.
4887 */
willy tarreaue39cd132005-12-17 13:00:18 +01004888 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01004889 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01004890 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01004891 if (!(t->flags & SN_ERR_MASK))
4892 t->flags |= SN_ERR_PRXCOND;
4893 if (!(t->flags & SN_FINST_MASK))
4894 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004895 return 1;
4896 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004897 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004898 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004899 tv_eternity(&t->crexpire);
4900 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004901 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004902 if (!(t->flags & SN_ERR_MASK))
4903 t->flags |= SN_ERR_CLICL;
4904 if (!(t->flags & SN_FINST_MASK))
4905 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004906 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004907 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004908 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4909
4910 /* read timeout : give up with an error message.
4911 */
4912 t->logs.status = 408;
4913 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004914 if (!(t->flags & SN_ERR_MASK))
4915 t->flags |= SN_ERR_CLITO;
4916 if (!(t->flags & SN_FINST_MASK))
4917 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004918 return 1;
4919 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004920
4921 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004922 }
4923 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004924 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004925 /* FIXME: this error handling is partly buggy because we always report
4926 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4927 * or HEADER phase. BTW, it's not logical to expire the client while
4928 * we're waiting for the server to connect.
4929 */
willy tarreau0f7af912005-12-17 12:21:26 +01004930 /* read or write error */
4931 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004932 tv_eternity(&t->crexpire);
4933 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004934 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004935 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004936 if (!(t->flags & SN_ERR_MASK))
4937 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004938 if (!(t->flags & SN_FINST_MASK)) {
4939 if (t->pend_pos)
4940 t->flags |= SN_FINST_Q;
4941 else if (s == SV_STCONN)
4942 t->flags |= SN_FINST_C;
4943 else
4944 t->flags |= SN_FINST_D;
4945 }
willy tarreau0f7af912005-12-17 12:21:26 +01004946 return 1;
4947 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004948 /* last read, or end of server write */
4949 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004950 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004951 tv_eternity(&t->crexpire);
4952 shutdown(t->cli_fd, SHUT_RD);
4953 t->cli_state = CL_STSHUTR;
4954 return 1;
4955 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004956 /* last server read and buffer empty */
4957 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004958 FD_CLR(t->cli_fd, StaticWriteEvent);
4959 tv_eternity(&t->cwexpire);
4960 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004961 /* We must ensure that the read part is still alive when switching
4962 * to shutw */
4963 FD_SET(t->cli_fd, StaticReadEvent);
4964 if (t->proxy->clitimeout)
4965 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004966 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004967 //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 +01004968 return 1;
4969 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004970 /* read timeout */
4971 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4972 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004973 tv_eternity(&t->crexpire);
4974 shutdown(t->cli_fd, SHUT_RD);
4975 t->cli_state = CL_STSHUTR;
4976 if (!(t->flags & SN_ERR_MASK))
4977 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004978 if (!(t->flags & SN_FINST_MASK)) {
4979 if (t->pend_pos)
4980 t->flags |= SN_FINST_Q;
4981 else if (s == SV_STCONN)
4982 t->flags |= SN_FINST_C;
4983 else
4984 t->flags |= SN_FINST_D;
4985 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004986 return 1;
4987 }
4988 /* write timeout */
4989 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4990 FD_CLR(t->cli_fd, StaticWriteEvent);
4991 tv_eternity(&t->cwexpire);
4992 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004993 /* We must ensure that the read part is still alive when switching
4994 * to shutw */
4995 FD_SET(t->cli_fd, StaticReadEvent);
4996 if (t->proxy->clitimeout)
4997 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4998
willy tarreau036e1ce2005-12-17 13:46:33 +01004999 t->cli_state = CL_STSHUTW;
5000 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01005001 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005002 if (!(t->flags & SN_FINST_MASK)) {
5003 if (t->pend_pos)
5004 t->flags |= SN_FINST_Q;
5005 else if (s == SV_STCONN)
5006 t->flags |= SN_FINST_C;
5007 else
5008 t->flags |= SN_FINST_D;
5009 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005010 return 1;
5011 }
willy tarreau0f7af912005-12-17 12:21:26 +01005012
willy tarreauc58fc692005-12-17 14:13:08 +01005013 if (req->l >= req->rlim - req->data) {
5014 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01005015 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01005016 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01005017 FD_CLR(t->cli_fd, StaticReadEvent);
5018 tv_eternity(&t->crexpire);
5019 }
5020 }
5021 else {
willy tarreauef900ab2005-12-17 12:52:52 +01005022 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01005023 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
5024 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01005025 if (!t->proxy->clitimeout ||
5026 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
5027 /* If the client has no timeout, or if the server not ready yet, and we
5028 * know for sure that it can expire, then it's cleaner to disable the
5029 * timeout on the client side so that too low values cannot make the
5030 * sessions abort too early.
5031 */
willy tarreau0f7af912005-12-17 12:21:26 +01005032 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01005033 else
5034 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005035 }
5036 }
5037
5038 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01005039 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005040 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5041 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
5042 tv_eternity(&t->cwexpire);
5043 }
5044 }
5045 else { /* buffer not empty */
5046 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5047 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005048 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005049 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005050 /* FIXME: to prevent the client from expiring read timeouts during writes,
5051 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005052 t->crexpire = t->cwexpire;
5053 }
willy tarreau0f7af912005-12-17 12:21:26 +01005054 else
5055 tv_eternity(&t->cwexpire);
5056 }
5057 }
5058 return 0; /* other cases change nothing */
5059 }
5060 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005061 if (t->res_cw == RES_ERROR) {
5062 tv_eternity(&t->cwexpire);
5063 fd_delete(t->cli_fd);
5064 t->cli_state = CL_STCLOSE;
5065 if (!(t->flags & SN_ERR_MASK))
5066 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02005067 if (!(t->flags & SN_FINST_MASK)) {
5068 if (t->pend_pos)
5069 t->flags |= SN_FINST_Q;
5070 else if (s == SV_STCONN)
5071 t->flags |= SN_FINST_C;
5072 else
5073 t->flags |= SN_FINST_D;
5074 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005075 return 1;
5076 }
willy tarreaue0331262006-05-15 03:02:46 +02005077 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
5078 && !(t->flags & SN_SELF_GEN)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005079 tv_eternity(&t->cwexpire);
5080 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005081 t->cli_state = CL_STCLOSE;
5082 return 1;
5083 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005084 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
5085 tv_eternity(&t->cwexpire);
5086 fd_delete(t->cli_fd);
5087 t->cli_state = CL_STCLOSE;
5088 if (!(t->flags & SN_ERR_MASK))
5089 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005090 if (!(t->flags & SN_FINST_MASK)) {
5091 if (t->pend_pos)
5092 t->flags |= SN_FINST_Q;
5093 else if (s == SV_STCONN)
5094 t->flags |= SN_FINST_C;
5095 else
5096 t->flags |= SN_FINST_D;
5097 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005098 return 1;
5099 }
willy tarreaue0331262006-05-15 03:02:46 +02005100
5101 if (t->flags & SN_SELF_GEN) {
5102 produce_content(t);
5103 if (rep->l == 0) {
5104 tv_eternity(&t->cwexpire);
5105 fd_delete(t->cli_fd);
5106 t->cli_state = CL_STCLOSE;
5107 return 1;
5108 }
5109 }
5110
5111 if ((rep->l == 0)
5112 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005113 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5114 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
5115 tv_eternity(&t->cwexpire);
5116 }
5117 }
5118 else { /* buffer not empty */
5119 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5120 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005121 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005122 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005123 /* FIXME: to prevent the client from expiring read timeouts during writes,
5124 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005125 t->crexpire = t->cwexpire;
5126 }
willy tarreau0f7af912005-12-17 12:21:26 +01005127 else
5128 tv_eternity(&t->cwexpire);
5129 }
5130 }
5131 return 0;
5132 }
5133 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005134 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005135 tv_eternity(&t->crexpire);
5136 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005137 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005138 if (!(t->flags & SN_ERR_MASK))
5139 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02005140 if (!(t->flags & SN_FINST_MASK)) {
5141 if (t->pend_pos)
5142 t->flags |= SN_FINST_Q;
5143 else if (s == SV_STCONN)
5144 t->flags |= SN_FINST_C;
5145 else
5146 t->flags |= SN_FINST_D;
5147 }
willy tarreau0f7af912005-12-17 12:21:26 +01005148 return 1;
5149 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005150 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
5151 tv_eternity(&t->crexpire);
5152 fd_delete(t->cli_fd);
5153 t->cli_state = CL_STCLOSE;
5154 return 1;
5155 }
5156 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
5157 tv_eternity(&t->crexpire);
5158 fd_delete(t->cli_fd);
5159 t->cli_state = CL_STCLOSE;
5160 if (!(t->flags & SN_ERR_MASK))
5161 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005162 if (!(t->flags & SN_FINST_MASK)) {
5163 if (t->pend_pos)
5164 t->flags |= SN_FINST_Q;
5165 else if (s == SV_STCONN)
5166 t->flags |= SN_FINST_C;
5167 else
5168 t->flags |= SN_FINST_D;
5169 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005170 return 1;
5171 }
willy tarreauef900ab2005-12-17 12:52:52 +01005172 else if (req->l >= req->rlim - req->data) {
5173 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01005174
5175 /* FIXME-20050705: is it possible for a client to maintain a session
5176 * after the timeout by sending more data after it receives a close ?
5177 */
5178
willy tarreau0f7af912005-12-17 12:21:26 +01005179 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01005180 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01005181 FD_CLR(t->cli_fd, StaticReadEvent);
5182 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01005183 //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 +01005184 }
5185 }
5186 else {
willy tarreauef900ab2005-12-17 12:52:52 +01005187 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01005188 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
5189 FD_SET(t->cli_fd, StaticReadEvent);
5190 if (t->proxy->clitimeout)
5191 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
5192 else
5193 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01005194 //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 +01005195 }
5196 }
5197 return 0;
5198 }
5199 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005200 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005201 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005202 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 +01005203 write(1, trash, len);
5204 }
5205 return 0;
5206 }
5207 return 0;
5208}
5209
willy tarreaudfece232006-05-02 00:19:57 +02005210/* This function turns the server state into the SV_STCLOSE, and sets
5211 * indicators accordingly. Note that if <status> is 0, no message is
5212 * returned.
5213 */
5214void srv_close_with_err(struct session *t, int err, int finst, int status, int msglen, char *msg) {
5215 t->srv_state = SV_STCLOSE;
5216 if (status > 0) {
5217 t->logs.status = status;
5218 if (t->proxy->mode == PR_MODE_HTTP)
5219 client_return(t, msglen, msg);
5220 }
5221 if (!(t->flags & SN_ERR_MASK))
5222 t->flags |= err;
5223 if (!(t->flags & SN_FINST_MASK))
5224 t->flags |= finst;
5225}
5226
5227/*
5228 * This function checks the retry count during the connect() job.
5229 * It updates the session's srv_state and retries, so that the caller knows
5230 * what it has to do. It uses the last connection error to set the log when
5231 * it expires. It returns 1 when it has expired, and 0 otherwise.
5232 */
5233int srv_count_retry_down(struct session *t, int conn_err) {
5234 /* we are in front of a retryable error */
5235 t->conn_retries--;
5236 if (t->conn_retries < 0) {
5237 /* if not retryable anymore, let's abort */
5238 tv_eternity(&t->cnexpire);
5239 srv_close_with_err(t, conn_err, SN_FINST_C,
5240 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaue3b30652006-05-21 16:23:22 +02005241 if (t->srv)
5242 t->srv->failed_conns++;
5243 t->proxy->failed_conns++;
5244
willy tarreaudfece232006-05-02 00:19:57 +02005245 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005246 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005247 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005248 if (may_dequeue_tasks(t->srv, t->proxy))
5249 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005250 return 1;
5251 }
5252 return 0;
5253}
willy tarreau0f7af912005-12-17 12:21:26 +01005254
5255/*
willy tarreaudfece232006-05-02 00:19:57 +02005256 * This function performs the retryable part of the connect() job.
5257 * It updates the session's srv_state and retries, so that the caller knows
5258 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
5259 * it needs to redispatch.
5260 */
5261int srv_retryable_connect(struct session *t) {
5262 int conn_err;
5263
5264 /* This loop ensures that we stop before the last retry in case of a
5265 * redispatchable server.
5266 */
5267 do {
5268 /* initiate a connection to the server */
5269 conn_err = connect_server(t);
5270 switch (conn_err) {
5271
5272 case SN_ERR_NONE:
5273 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
5274 t->srv_state = SV_STCONN;
5275 return 1;
5276
5277 case SN_ERR_INTERNAL:
5278 tv_eternity(&t->cnexpire);
5279 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
5280 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreaue3b30652006-05-21 16:23:22 +02005281 if (t->srv)
5282 t->srv->failed_conns++;
5283 t->proxy->failed_conns++;
willy tarreaudfece232006-05-02 00:19:57 +02005284 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02005285 if (may_dequeue_tasks(t->srv, t->proxy))
5286 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005287 return 1;
5288 }
5289 /* ensure that we have enough retries left */
willy tarreau59a6cc22006-05-12 01:29:08 +02005290 if (srv_count_retry_down(t, conn_err)) {
5291 /* let's try to offer this slot to anybody */
5292 if (may_dequeue_tasks(t->srv, t->proxy))
5293 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005294 return 1;
willy tarreau59a6cc22006-05-12 01:29:08 +02005295 }
willy tarreaudfece232006-05-02 00:19:57 +02005296 } while (t->srv == NULL || t->conn_retries > 0 || !(t->proxy->options & PR_O_REDISP));
5297
5298 /* We're on our last chance, and the REDISP option was specified.
5299 * We will ignore cookie and force to balance or use the dispatcher.
5300 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005301 /* let's try to offer this slot to anybody */
5302 if (may_dequeue_tasks(t->srv, t->proxy))
5303 task_wakeup(&rq, t->srv->queue_mgt);
5304
willy tarreaue3b30652006-05-21 16:23:22 +02005305 if (t->srv)
5306 t->srv->failed_conns++;
5307 t->proxy->failed_conns++;
5308
willy tarreaudfece232006-05-02 00:19:57 +02005309 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
5310 t->srv = NULL; /* it's left to the dispatcher to choose a server */
5311 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
5312 t->flags &= ~SN_CK_MASK;
5313 t->flags |= SN_CK_DOWN;
5314 }
5315 return 0;
5316}
5317
5318/* This function performs the "redispatch" part of a connection attempt. It
5319 * will assign a server if required, queue the connection if required, and
5320 * handle errors that might arise at this level. It can change the server
5321 * state. It will return 1 if it encounters an error, switches the server
5322 * state, or has to queue a connection. Otherwise, it will return 0 indicating
5323 * that the connection is ready to use.
5324 */
5325
5326int srv_redispatch_connect(struct session *t) {
5327 int conn_err;
5328
5329 /* We know that we don't have any connection pending, so we will
5330 * try to get a new one, and wait in this state if it's queued
5331 */
5332 conn_err = assign_server_and_queue(t);
5333 switch (conn_err) {
5334 case SRV_STATUS_OK:
5335 break;
5336
5337 case SRV_STATUS_NOSRV:
willy tarreau59a6cc22006-05-12 01:29:08 +02005338 /* note: it is guaranteed that t->srv == NULL here */
willy tarreaudfece232006-05-02 00:19:57 +02005339 tv_eternity(&t->cnexpire);
5340 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
5341 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaue3b30652006-05-21 16:23:22 +02005342 if (t->srv)
5343 t->srv->failed_conns++;
5344 t->proxy->failed_conns++;
5345
willy tarreaudfece232006-05-02 00:19:57 +02005346 return 1;
5347
5348 case SRV_STATUS_QUEUED:
willy tarreau45526ed2006-05-03 20:11:50 +02005349 /* FIXME-20060503 : we should use the queue timeout instead */
5350 if (t->proxy->contimeout)
5351 tv_delayfrom(&t->cnexpire, &now, t->proxy->contimeout);
5352 else
5353 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02005354 t->srv_state = SV_STIDLE;
5355 /* do nothing else and do not wake any other session up */
5356 return 1;
5357
5358 case SRV_STATUS_FULL:
5359 case SRV_STATUS_INTERNAL:
5360 default:
5361 tv_eternity(&t->cnexpire);
5362 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
5363 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreaue3b30652006-05-21 16:23:22 +02005364 if (t->srv)
5365 t->srv->failed_conns++;
5366 t->proxy->failed_conns++;
5367
willy tarreaudfece232006-05-02 00:19:57 +02005368 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02005369 if (may_dequeue_tasks(t->srv, t->proxy))
5370 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005371 return 1;
5372 }
5373 /* if we get here, it's because we got SRV_STATUS_OK, which also
5374 * means that the connection has not been queued.
5375 */
5376 return 0;
5377}
5378
5379
5380/*
willy tarreau0f7af912005-12-17 12:21:26 +01005381 * manages the server FSM and its socket. It returns 1 if a state has changed
5382 * (and a resync may be needed), 0 else.
5383 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005384int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01005385 int s = t->srv_state;
5386 int c = t->cli_state;
5387 struct buffer *req = t->req;
5388 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01005389 appsess *asession_temp = NULL;
5390 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01005391 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01005392
willy tarreau750a4722005-12-17 13:21:24 +01005393#ifdef DEBUG_FULL
5394 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
5395#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01005396 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
5397 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
5398 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
5399 //);
willy tarreau0f7af912005-12-17 12:21:26 +01005400 if (s == SV_STIDLE) {
5401 if (c == CL_STHEADERS)
5402 return 0; /* stay in idle, waiting for data to reach the client side */
willy tarreau03a92de2006-05-21 18:26:53 +02005403 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
5404 (c == CL_STSHUTR &&
5405 (t->req->l == 0 || t->proxy->options & PR_O_ABRT_CLOSE))) { /* give up */
willy tarreau0f7af912005-12-17 12:21:26 +01005406 tv_eternity(&t->cnexpire);
willy tarreau424e04a2006-05-13 16:08:47 +02005407 if (t->pend_pos)
5408 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreau51e91292006-05-14 23:29:47 +02005409 /* note that this must not return any error because it would be able to
5410 * overwrite the client_retnclose() output.
5411 */
willy tarreau078c79a2006-05-13 12:23:58 +02005412 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 +02005413
willy tarreau0f7af912005-12-17 12:21:26 +01005414 return 1;
5415 }
willy tarreaudfece232006-05-02 00:19:57 +02005416 else {
5417 /* Right now, we will need to create a connection to the server.
5418 * We might already have tried, and got a connection pending, in
5419 * which case we will not do anything till it's pending. It's up
5420 * to any other session to release it and wake us up again.
5421 */
willy tarreau45526ed2006-05-03 20:11:50 +02005422 if (t->pend_pos) {
5423 if (tv_cmp2_ms(&t->cnexpire, &now) > 0)
5424 return 0;
5425 else {
5426 /* we've been waiting too long here */
5427 tv_eternity(&t->cnexpire);
willy tarreau078c79a2006-05-13 12:23:58 +02005428 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
5429 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
willy tarreau45526ed2006-05-03 20:11:50 +02005430 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaue3b30652006-05-21 16:23:22 +02005431 if (t->srv)
5432 t->srv->failed_conns++;
5433 t->proxy->failed_conns++;
willy tarreau45526ed2006-05-03 20:11:50 +02005434 return 1;
5435 }
5436 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005437
willy tarreaudfece232006-05-02 00:19:57 +02005438 do {
5439 /* first, get a connection */
5440 if (srv_redispatch_connect(t))
5441 return t->srv_state != SV_STIDLE;
5442
5443 /* try to (re-)connect to the server, and fail if we expire the
5444 * number of retries.
5445 */
willy tarreauf32f5242006-05-02 22:54:52 +02005446 if (srv_retryable_connect(t)) {
5447 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02005448 return t->srv_state != SV_STIDLE;
willy tarreauf32f5242006-05-02 22:54:52 +02005449 }
willy tarreaudfece232006-05-02 00:19:57 +02005450
5451 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01005452 }
5453 }
5454 else if (s == SV_STCONN) { /* connection in progress */
willy tarreau03a92de2006-05-21 18:26:53 +02005455 if (c == CL_STCLOSE || c == CL_STSHUTW ||
5456 (c == CL_STSHUTR &&
5457 (t->req->l == 0 || t->proxy->options & PR_O_ABRT_CLOSE))) { /* give up */
5458 tv_eternity(&t->cnexpire);
5459 fd_delete(t->srv_fd);
5460 if (t->srv)
5461 t->srv->cur_sess--;
5462
5463 /* note that this must not return any error because it would be able to
5464 * overwrite the client_retnclose() output.
5465 */
5466 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, 0, NULL);
5467 return 1;
5468 }
willy tarreau0f7af912005-12-17 12:21:26 +01005469 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01005470 //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 +01005471 return 0; /* nothing changed */
5472 }
5473 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
willy tarreaudfece232006-05-02 00:19:57 +02005474 /* timeout, asynchronous connect error or first write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005475 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
willy tarreaudfece232006-05-02 00:19:57 +02005476
willy tarreau0f7af912005-12-17 12:21:26 +01005477 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005478 if (t->srv)
5479 t->srv->cur_sess--;
willy tarreaudfece232006-05-02 00:19:57 +02005480
5481 if (t->res_sw == RES_SILENT)
willy tarreaub1285d52005-12-18 01:20:14 +01005482 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
5483 else
willy tarreaudfece232006-05-02 00:19:57 +02005484 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
willy tarreaub1285d52005-12-18 01:20:14 +01005485
willy tarreaudfece232006-05-02 00:19:57 +02005486 /* ensure that we have enough retries left */
5487 if (srv_count_retry_down(t, conn_err))
5488 return 1;
5489
5490 do {
5491 /* Now we will try to either reconnect to the same server or
5492 * connect to another server. If the connection gets queued
5493 * because all servers are saturated, then we will go back to
5494 * the SV_STIDLE state.
5495 */
willy tarreauf32f5242006-05-02 22:54:52 +02005496 if (srv_retryable_connect(t)) {
5497 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02005498 return t->srv_state != SV_STCONN;
willy tarreauf32f5242006-05-02 22:54:52 +02005499 }
willy tarreaudfece232006-05-02 00:19:57 +02005500
5501 /* we need to redispatch the connection to another server */
5502 if (srv_redispatch_connect(t))
5503 return t->srv_state != SV_STCONN;
5504 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01005505 }
5506 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01005507 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005508
willy tarreau0f7af912005-12-17 12:21:26 +01005509 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005510 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01005511 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005512 tv_eternity(&t->swexpire);
5513 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01005514 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005515 if (t->proxy->srvtimeout) {
5516 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005517 /* FIXME: to prevent the server from expiring read timeouts during writes,
5518 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005519 t->srexpire = t->swexpire;
5520 }
5521 else
5522 tv_eternity(&t->swexpire);
5523 }
willy tarreau0f7af912005-12-17 12:21:26 +01005524
5525 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
5526 FD_SET(t->srv_fd, StaticReadEvent);
5527 if (t->proxy->srvtimeout)
5528 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5529 else
5530 tv_eternity(&t->srexpire);
5531
5532 t->srv_state = SV_STDATA;
willy tarreau2d505e52006-05-21 08:32:50 +02005533 if (t->srv)
5534 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01005535 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01005536
5537 /* if the user wants to log as soon as possible, without counting
5538 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005539 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005540 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
5541 sess_log(t);
5542 }
willy tarreau0f7af912005-12-17 12:21:26 +01005543 }
willy tarreauef900ab2005-12-17 12:52:52 +01005544 else {
willy tarreau0f7af912005-12-17 12:21:26 +01005545 t->srv_state = SV_STHEADERS;
willy tarreau2d505e52006-05-21 08:32:50 +02005546 if (t->srv)
5547 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01005548 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
5549 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005550 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005551 return 1;
5552 }
5553 }
5554 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005555 /* now parse the partial (or complete) headers */
5556 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
5557 char *ptr;
5558 int delete_header;
5559
5560 ptr = rep->lr;
5561
5562 /* look for the end of the current header */
5563 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
5564 ptr++;
5565
5566 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005567 int line, len;
5568
5569 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01005570
5571 /* first, we'll block if security checks have caught nasty things */
5572 if (t->flags & SN_CACHEABLE) {
5573 if ((t->flags & SN_CACHE_COOK) &&
5574 (t->flags & SN_SCK_ANY) &&
5575 (t->proxy->options & PR_O_CHK_CACHE)) {
5576
5577 /* we're in presence of a cacheable response containing
5578 * a set-cookie header. We'll block it as requested by
5579 * the 'checkcache' option, and send an alert.
5580 */
5581 tv_eternity(&t->srexpire);
5582 tv_eternity(&t->swexpire);
5583 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02005584 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02005585 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02005586 t->srv->failed_secu++;
5587 }
5588 t->proxy->failed_secu++;
willy tarreau97f58572005-12-18 00:53:44 +01005589 t->srv_state = SV_STCLOSE;
5590 t->logs.status = 502;
5591 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
5592 if (!(t->flags & SN_ERR_MASK))
5593 t->flags |= SN_ERR_PRXCOND;
5594 if (!(t->flags & SN_FINST_MASK))
5595 t->flags |= SN_FINST_H;
5596
5597 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
5598 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
5599
willy tarreaudfece232006-05-02 00:19:57 +02005600 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005601 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005602 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005603 if (may_dequeue_tasks(t->srv, t->proxy))
5604 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005605
willy tarreau97f58572005-12-18 00:53:44 +01005606 return 1;
5607 }
5608 }
5609
willy tarreau982249e2005-12-18 00:57:06 +01005610 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
5611 if (t->flags & SN_SVDENY) {
5612 tv_eternity(&t->srexpire);
5613 tv_eternity(&t->swexpire);
5614 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02005615 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02005616 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02005617 t->srv->failed_secu++;
5618 }
5619 t->proxy->failed_secu++;
willy tarreau982249e2005-12-18 00:57:06 +01005620 t->srv_state = SV_STCLOSE;
5621 t->logs.status = 502;
5622 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
5623 if (!(t->flags & SN_ERR_MASK))
5624 t->flags |= SN_ERR_PRXCOND;
5625 if (!(t->flags & SN_FINST_MASK))
5626 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005627 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005628 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005629 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005630 if (may_dequeue_tasks(t->srv, t->proxy))
5631 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005632
willy tarreau982249e2005-12-18 00:57:06 +01005633 return 1;
5634 }
5635
willy tarreau5cbea6f2005-12-17 12:48:26 +01005636 /* we'll have something else to do here : add new headers ... */
5637
willy tarreaucd878942005-12-17 13:27:43 +01005638 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
5639 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005640 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01005641 * insert a set-cookie here, except if we want to insert only on POST
willy tarreau4f7a1012006-05-09 23:32:26 +02005642 * requests and this one isn't. Note that servers which don't have cookies
5643 * (eg: some backup servers) will return a full cookie removal request.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005644 */
willy tarreau750a4722005-12-17 13:21:24 +01005645 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01005646 t->proxy->cookie_name,
willy tarreau4f7a1012006-05-09 23:32:26 +02005647 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
willy tarreau750a4722005-12-17 13:21:24 +01005648
willy tarreau036e1ce2005-12-17 13:46:33 +01005649 t->flags |= SN_SCK_INSERTED;
5650
willy tarreau750a4722005-12-17 13:21:24 +01005651 /* Here, we will tell an eventual cache on the client side that we don't
5652 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
5653 * Some caches understand the correct form: 'no-cache="set-cookie"', but
5654 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
5655 */
willy tarreau240afa62005-12-17 13:14:35 +01005656 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01005657 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
5658 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01005659
5660 if (rep->data + rep->l < rep->h)
5661 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
5662 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01005663 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005664 }
5665
5666 /* headers to be added */
5667 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01005668 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
5669 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005670 }
5671
willy tarreau25c4ea52005-12-18 00:49:49 +01005672 /* add a "connection: close" line if needed */
5673 if (t->proxy->options & PR_O_HTTP_CLOSE)
5674 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
5675
willy tarreau5cbea6f2005-12-17 12:48:26 +01005676 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01005677 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01005678 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01005679
Willy TARREAU767ba712006-03-01 22:40:50 +01005680 /* client connection already closed or option 'httpclose' required :
5681 * we close the server's outgoing connection right now.
5682 */
5683 if ((req->l == 0) &&
5684 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
5685 FD_CLR(t->srv_fd, StaticWriteEvent);
5686 tv_eternity(&t->swexpire);
5687
5688 /* We must ensure that the read part is still alive when switching
5689 * to shutw */
5690 FD_SET(t->srv_fd, StaticReadEvent);
5691 if (t->proxy->srvtimeout)
5692 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5693
5694 shutdown(t->srv_fd, SHUT_WR);
5695 t->srv_state = SV_STSHUTW;
5696 }
5697
willy tarreau25c4ea52005-12-18 00:49:49 +01005698 /* if the user wants to log as soon as possible, without counting
5699 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005700 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005701 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
5702 t->logs.bytes = rep->h - rep->data;
5703 sess_log(t);
5704 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005705 break;
5706 }
5707
5708 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
5709 if (ptr > rep->r - 2) {
5710 /* this is a partial header, let's wait for more to come */
5711 rep->lr = ptr;
5712 break;
5713 }
5714
5715 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
5716 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
5717
5718 /* now we know that *ptr is either \r or \n,
5719 * and that there are at least 1 char after it.
5720 */
5721 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
5722 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
5723 else
5724 rep->lr = ptr + 2; /* \r\n or \n\r */
5725
5726 /*
5727 * now we know that we have a full header ; we can do whatever
5728 * we want with these pointers :
5729 * rep->h = beginning of header
5730 * ptr = end of header (first \r or \n)
5731 * rep->lr = beginning of next line (next rep->h)
5732 * rep->r = end of data (not used at this stage)
5733 */
5734
willy tarreaua1598082005-12-17 13:08:06 +01005735
willy tarreau982249e2005-12-18 00:57:06 +01005736 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01005737 t->logs.logwait &= ~LW_RESP;
5738 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01005739 switch (t->logs.status) {
5740 case 200:
5741 case 203:
5742 case 206:
5743 case 300:
5744 case 301:
5745 case 410:
5746 /* RFC2616 @13.4:
5747 * "A response received with a status code of
5748 * 200, 203, 206, 300, 301 or 410 MAY be stored
5749 * by a cache (...) unless a cache-control
5750 * directive prohibits caching."
5751 *
5752 * RFC2616 @9.5: POST method :
5753 * "Responses to this method are not cacheable,
5754 * unless the response includes appropriate
5755 * Cache-Control or Expires header fields."
5756 */
willy tarreau7476ec92006-05-21 16:24:15 +02005757 if (!(t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
willy tarreau982249e2005-12-18 00:57:06 +01005758 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
5759 break;
5760 default:
5761 break;
5762 }
willy tarreau4302f492005-12-18 01:00:37 +01005763 }
5764 else if (t->logs.logwait & LW_RSPHDR) {
5765 struct cap_hdr *h;
5766 int len;
5767 for (h = t->proxy->rsp_cap; h; h = h->next) {
5768 if ((h->namelen + 2 <= ptr - rep->h) &&
5769 (rep->h[h->namelen] == ':') &&
5770 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
5771
5772 if (t->rsp_cap[h->index] == NULL)
5773 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
5774
5775 len = ptr - (rep->h + h->namelen + 2);
5776 if (len > h->len)
5777 len = h->len;
5778
5779 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
5780 t->rsp_cap[h->index][len]=0;
5781 }
5782 }
5783
willy tarreaua1598082005-12-17 13:08:06 +01005784 }
5785
willy tarreau5cbea6f2005-12-17 12:48:26 +01005786 delete_header = 0;
5787
willy tarreau982249e2005-12-18 00:57:06 +01005788 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005789 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01005790 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 +01005791 max = ptr - rep->h;
5792 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01005793 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005794 trash[len++] = '\n';
5795 write(1, trash, len);
5796 }
5797
willy tarreau25c4ea52005-12-18 00:49:49 +01005798 /* remove "connection: " if needed */
5799 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
5800 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
5801 delete_header = 1;
5802 }
5803
willy tarreau5cbea6f2005-12-17 12:48:26 +01005804 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01005805 if (!delete_header && t->proxy->rsp_exp != NULL
5806 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01005807 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005808 char term;
5809
5810 term = *ptr;
5811 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01005812 exp = t->proxy->rsp_exp;
5813 do {
5814 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
5815 switch (exp->action) {
5816 case ACT_ALLOW:
5817 if (!(t->flags & SN_SVDENY))
5818 t->flags |= SN_SVALLOW;
5819 break;
5820 case ACT_REPLACE:
5821 if (!(t->flags & SN_SVDENY)) {
5822 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
5823 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
5824 }
5825 break;
5826 case ACT_REMOVE:
5827 if (!(t->flags & SN_SVDENY))
5828 delete_header = 1;
5829 break;
5830 case ACT_DENY:
5831 if (!(t->flags & SN_SVALLOW))
5832 t->flags |= SN_SVDENY;
5833 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01005834 case ACT_PASS: /* we simply don't deny this one */
5835 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005836 }
5837 break;
5838 }
willy tarreaue39cd132005-12-17 13:00:18 +01005839 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005840 *ptr = term; /* restore the string terminator */
5841 }
5842
willy tarreau97f58572005-12-18 00:53:44 +01005843 /* check for cache-control: or pragma: headers */
5844 if (!delete_header && (t->flags & SN_CACHEABLE)) {
5845 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
5846 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5847 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
5848 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01005849 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01005850 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5851 else {
5852 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01005853 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005854 t->flags &= ~SN_CACHE_COOK;
5855 }
5856 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005857 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005858 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005859 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01005860 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5861 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005862 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01005863 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01005864 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
5865 (rep->h + 25 == ptr || rep->h[25] == ',')) {
5866 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5867 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
5868 (rep->h + 21 == ptr || rep->h[21] == ',')) {
5869 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01005870 }
5871 }
5872 }
5873
willy tarreau5cbea6f2005-12-17 12:48:26 +01005874 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01005875 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01005876 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01005877 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005878 char *p1, *p2, *p3, *p4;
5879
willy tarreau97f58572005-12-18 00:53:44 +01005880 t->flags |= SN_SCK_ANY;
5881
willy tarreau5cbea6f2005-12-17 12:48:26 +01005882 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
5883
5884 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01005885 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005886 p1++;
5887
5888 if (p1 == ptr || *p1 == ';') /* end of cookie */
5889 break;
5890
5891 /* p1 is at the beginning of the cookie name */
5892 p2 = p1;
5893
5894 while (p2 < ptr && *p2 != '=' && *p2 != ';')
5895 p2++;
5896
5897 if (p2 == ptr || *p2 == ';') /* next cookie */
5898 break;
5899
5900 p3 = p2 + 1; /* skips the '=' sign */
5901 if (p3 == ptr)
5902 break;
5903
5904 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01005905 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01005906 p4++;
5907
5908 /* here, we have the cookie name between p1 and p2,
5909 * and its value between p3 and p4.
5910 * we can process it.
5911 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005912
5913 /* first, let's see if we want to capture it */
5914 if (t->proxy->capture_name != NULL &&
5915 t->logs.srv_cookie == NULL &&
5916 (p4 - p1 >= t->proxy->capture_namelen) &&
5917 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
5918 int log_len = p4 - p1;
5919
5920 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
5921 Alert("HTTP logging : out of memory.\n");
5922 }
5923
5924 if (log_len > t->proxy->capture_len)
5925 log_len = t->proxy->capture_len;
5926 memcpy(t->logs.srv_cookie, p1, log_len);
5927 t->logs.srv_cookie[log_len] = 0;
5928 }
5929
5930 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
5931 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005932 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01005933 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005934
5935 /* If the cookie is in insert mode on a known server, we'll delete
5936 * this occurrence because we'll insert another one later.
5937 * We'll delete it too if the "indirect" option is set and we're in
5938 * a direct access. */
5939 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01005940 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005941 /* this header must be deleted */
5942 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01005943 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005944 }
5945 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
5946 /* replace bytes p3->p4 with the cookie name associated
5947 * with this server since we know it.
5948 */
5949 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01005950 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005951 }
willy tarreau0174f312005-12-18 01:02:42 +01005952 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
5953 /* insert the cookie name associated with this server
5954 * before existing cookie, and insert a delimitor between them..
5955 */
5956 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
5957 p3[t->srv->cklen] = COOKIE_DELIM;
5958 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
5959 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005960 break;
5961 }
willy tarreau12350152005-12-18 01:03:27 +01005962
5963 /* first, let's see if the cookie is our appcookie*/
5964 if ((t->proxy->appsession_name != NULL) &&
5965 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
5966
5967 /* Cool... it's the right one */
5968
willy tarreaub952e1d2005-12-18 01:31:20 +01005969 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01005970 asession_temp = &local_asession;
5971
willy tarreaub952e1d2005-12-18 01:31:20 +01005972 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005973 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5974 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5975 }
5976 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
5977 asession_temp->sessid[t->proxy->appsession_len] = 0;
5978 asession_temp->serverid = NULL;
5979
5980 /* only do insert, if lookup fails */
5981 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
5982 if ((asession_temp = pool_alloc(appsess)) == NULL) {
5983 Alert("Not enought Memory process_srv():asession:calloc().\n");
5984 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
5985 return 0;
5986 }
5987 asession_temp->sessid = local_asession.sessid;
5988 asession_temp->serverid = local_asession.serverid;
5989 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01005990 }/* end if (chtbl_lookup()) */
5991 else {
willy tarreau12350152005-12-18 01:03:27 +01005992 /* free wasted memory */
5993 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01005994 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01005995
willy tarreaub952e1d2005-12-18 01:31:20 +01005996 if (asession_temp->serverid == NULL) {
5997 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005998 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5999 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
6000 }
6001 asession_temp->serverid[0] = '\0';
6002 }
6003
willy tarreaub952e1d2005-12-18 01:31:20 +01006004 if (asession_temp->serverid[0] == '\0')
6005 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01006006
6007 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
6008
6009#if defined(DEBUG_HASH)
6010 print_table(&(t->proxy->htbl_proxy));
6011#endif
6012 break;
6013 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006014 else {
6015 // fprintf(stderr,"Ignoring unknown cookie : ");
6016 // write(2, p1, p2-p1);
6017 // fprintf(stderr," = ");
6018 // write(2, p3, p4-p3);
6019 // fprintf(stderr,"\n");
6020 }
6021 break; /* we don't want to loop again since there cannot be another cookie on the same line */
6022 } /* we're now at the end of the cookie value */
6023 } /* end of cookie processing */
6024
willy tarreau97f58572005-12-18 00:53:44 +01006025 /* check for any set-cookie in case we check for cacheability */
6026 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
6027 (t->proxy->options & PR_O_CHK_CACHE) &&
6028 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
6029 t->flags |= SN_SCK_ANY;
6030 }
6031
willy tarreau5cbea6f2005-12-17 12:48:26 +01006032 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01006033 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006034 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01006035
willy tarreau5cbea6f2005-12-17 12:48:26 +01006036 rep->h = rep->lr;
6037 } /* while (rep->lr < rep->r) */
6038
6039 /* end of header processing (even if incomplete) */
6040
willy tarreauef900ab2005-12-17 12:52:52 +01006041 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6042 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
6043 * full. We cannot loop here since event_srv_read will disable it only if
6044 * rep->l == rlim-data
6045 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006046 FD_SET(t->srv_fd, StaticReadEvent);
6047 if (t->proxy->srvtimeout)
6048 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6049 else
6050 tv_eternity(&t->srexpire);
6051 }
willy tarreau0f7af912005-12-17 12:21:26 +01006052
willy tarreau8337c6b2005-12-17 13:41:01 +01006053 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01006054 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01006055 tv_eternity(&t->srexpire);
6056 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006057 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006058 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006059 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006060 t->srv->failed_resp++;
6061 }
6062 t->proxy->failed_resp++;
6063
willy tarreau0f7af912005-12-17 12:21:26 +01006064 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01006065 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01006066 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01006067 if (!(t->flags & SN_ERR_MASK))
6068 t->flags |= SN_ERR_SRVCL;
6069 if (!(t->flags & SN_FINST_MASK))
6070 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02006071 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006072 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006073 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006074 if (may_dequeue_tasks(t->srv, t->proxy))
6075 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006076
willy tarreau0f7af912005-12-17 12:21:26 +01006077 return 1;
6078 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006079 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01006080 * since we are in header mode, if there's no space left for headers, we
6081 * won't be able to free more later, so the session will never terminate.
6082 */
willy tarreau8337c6b2005-12-17 13:41:01 +01006083 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 +01006084 FD_CLR(t->srv_fd, StaticReadEvent);
6085 tv_eternity(&t->srexpire);
6086 shutdown(t->srv_fd, SHUT_RD);
6087 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01006088 //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 +01006089 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006090 }
6091 /* read timeout : return a 504 to the client.
6092 */
6093 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6094 tv_eternity(&t->srexpire);
6095 tv_eternity(&t->swexpire);
6096 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006097 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006098 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006099 t->srv->failed_resp++;
6100 }
6101 t->proxy->failed_resp++;
willy tarreau8337c6b2005-12-17 13:41:01 +01006102 t->srv_state = SV_STCLOSE;
6103 t->logs.status = 504;
6104 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01006105 if (!(t->flags & SN_ERR_MASK))
6106 t->flags |= SN_ERR_SRVTO;
6107 if (!(t->flags & SN_FINST_MASK))
6108 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02006109 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006110 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006111 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006112 if (may_dequeue_tasks(t->srv, t->proxy))
6113 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006114
willy tarreau8337c6b2005-12-17 13:41:01 +01006115 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006116 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006117 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01006118 /* FIXME!!! here, we don't want to switch to SHUTW if the
6119 * client shuts read too early, because we may still have
6120 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01006121 * The side-effect is that if the client completely closes its
6122 * connection during SV_STHEADER, the connection to the server
6123 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01006124 */
willy tarreau036e1ce2005-12-17 13:46:33 +01006125 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01006126 FD_CLR(t->srv_fd, StaticWriteEvent);
6127 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01006128
6129 /* We must ensure that the read part is still alive when switching
6130 * to shutw */
6131 FD_SET(t->srv_fd, StaticReadEvent);
6132 if (t->proxy->srvtimeout)
6133 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6134
willy tarreau0f7af912005-12-17 12:21:26 +01006135 shutdown(t->srv_fd, SHUT_WR);
6136 t->srv_state = SV_STSHUTW;
6137 return 1;
6138 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006139 /* write timeout */
6140 /* FIXME!!! here, we don't want to switch to SHUTW if the
6141 * client shuts read too early, because we may still have
6142 * some work to do on the headers.
6143 */
6144 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
6145 FD_CLR(t->srv_fd, StaticWriteEvent);
6146 tv_eternity(&t->swexpire);
6147 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006148 /* We must ensure that the read part is still alive when switching
6149 * to shutw */
6150 FD_SET(t->srv_fd, StaticReadEvent);
6151 if (t->proxy->srvtimeout)
6152 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6153
6154 /* We must ensure that the read part is still alive when switching
6155 * to shutw */
6156 FD_SET(t->srv_fd, StaticReadEvent);
6157 if (t->proxy->srvtimeout)
6158 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6159
willy tarreau036e1ce2005-12-17 13:46:33 +01006160 t->srv_state = SV_STSHUTW;
6161 if (!(t->flags & SN_ERR_MASK))
6162 t->flags |= SN_ERR_SRVTO;
6163 if (!(t->flags & SN_FINST_MASK))
6164 t->flags |= SN_FINST_H;
6165 return 1;
6166 }
willy tarreau0f7af912005-12-17 12:21:26 +01006167
6168 if (req->l == 0) {
6169 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6170 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6171 tv_eternity(&t->swexpire);
6172 }
6173 }
6174 else { /* client buffer not empty */
6175 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6176 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006177 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006178 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006179 /* FIXME: to prevent the server from expiring read timeouts during writes,
6180 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006181 t->srexpire = t->swexpire;
6182 }
willy tarreau0f7af912005-12-17 12:21:26 +01006183 else
6184 tv_eternity(&t->swexpire);
6185 }
6186 }
6187
willy tarreau5cbea6f2005-12-17 12:48:26 +01006188 /* be nice with the client side which would like to send a complete header
6189 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
6190 * would read all remaining data at once ! The client should not write past rep->lr
6191 * when the server is in header state.
6192 */
6193 //return header_processed;
6194 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01006195 }
6196 else if (s == SV_STDATA) {
6197 /* read or write error */
6198 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01006199 tv_eternity(&t->srexpire);
6200 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006201 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006202 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006203 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006204 t->srv->failed_resp++;
6205 }
6206 t->proxy->failed_resp++;
willy tarreau0f7af912005-12-17 12:21:26 +01006207 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01006208 if (!(t->flags & SN_ERR_MASK))
6209 t->flags |= SN_ERR_SRVCL;
6210 if (!(t->flags & SN_FINST_MASK))
6211 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006212 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006213 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006214 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006215 if (may_dequeue_tasks(t->srv, t->proxy))
6216 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006217
willy tarreau0f7af912005-12-17 12:21:26 +01006218 return 1;
6219 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006220 /* last read, or end of client write */
6221 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01006222 FD_CLR(t->srv_fd, StaticReadEvent);
6223 tv_eternity(&t->srexpire);
6224 shutdown(t->srv_fd, SHUT_RD);
6225 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01006226 //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 +01006227 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01006228 }
6229 /* end of client read and no more data to send */
6230 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
6231 FD_CLR(t->srv_fd, StaticWriteEvent);
6232 tv_eternity(&t->swexpire);
6233 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006234 /* We must ensure that the read part is still alive when switching
6235 * to shutw */
6236 FD_SET(t->srv_fd, StaticReadEvent);
6237 if (t->proxy->srvtimeout)
6238 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6239
willy tarreaua41a8b42005-12-17 14:02:24 +01006240 t->srv_state = SV_STSHUTW;
6241 return 1;
6242 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006243 /* read timeout */
6244 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6245 FD_CLR(t->srv_fd, StaticReadEvent);
6246 tv_eternity(&t->srexpire);
6247 shutdown(t->srv_fd, SHUT_RD);
6248 t->srv_state = SV_STSHUTR;
6249 if (!(t->flags & SN_ERR_MASK))
6250 t->flags |= SN_ERR_SRVTO;
6251 if (!(t->flags & SN_FINST_MASK))
6252 t->flags |= SN_FINST_D;
6253 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006254 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006255 /* write timeout */
6256 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01006257 FD_CLR(t->srv_fd, StaticWriteEvent);
6258 tv_eternity(&t->swexpire);
6259 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006260 /* We must ensure that the read part is still alive when switching
6261 * to shutw */
6262 FD_SET(t->srv_fd, StaticReadEvent);
6263 if (t->proxy->srvtimeout)
6264 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01006265 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01006266 if (!(t->flags & SN_ERR_MASK))
6267 t->flags |= SN_ERR_SRVTO;
6268 if (!(t->flags & SN_FINST_MASK))
6269 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01006270 return 1;
6271 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01006272
6273 /* recompute request time-outs */
6274 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01006275 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6276 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6277 tv_eternity(&t->swexpire);
6278 }
6279 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01006280 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01006281 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6282 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006283 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006284 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006285 /* FIXME: to prevent the server from expiring read timeouts during writes,
6286 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006287 t->srexpire = t->swexpire;
6288 }
willy tarreau0f7af912005-12-17 12:21:26 +01006289 else
6290 tv_eternity(&t->swexpire);
6291 }
6292 }
6293
willy tarreaub1ff9db2005-12-17 13:51:03 +01006294 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01006295 if (rep->l == BUFSIZE) { /* no room to read more data */
6296 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
6297 FD_CLR(t->srv_fd, StaticReadEvent);
6298 tv_eternity(&t->srexpire);
6299 }
6300 }
6301 else {
6302 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6303 FD_SET(t->srv_fd, StaticReadEvent);
6304 if (t->proxy->srvtimeout)
6305 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6306 else
6307 tv_eternity(&t->srexpire);
6308 }
6309 }
6310
6311 return 0; /* other cases change nothing */
6312 }
6313 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006314 if (t->res_sw == RES_ERROR) {
6315 //FD_CLR(t->srv_fd, StaticWriteEvent);
6316 tv_eternity(&t->swexpire);
6317 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006318 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006319 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006320 t->srv->failed_resp++;
6321 }
6322 t->proxy->failed_resp++;
willy tarreau036e1ce2005-12-17 13:46:33 +01006323 //close(t->srv_fd);
6324 t->srv_state = SV_STCLOSE;
6325 if (!(t->flags & SN_ERR_MASK))
6326 t->flags |= SN_ERR_SRVCL;
6327 if (!(t->flags & SN_FINST_MASK))
6328 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006329 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006330 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006331 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006332 if (may_dequeue_tasks(t->srv, t->proxy))
6333 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006334
willy tarreau036e1ce2005-12-17 13:46:33 +01006335 return 1;
6336 }
6337 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006338 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01006339 tv_eternity(&t->swexpire);
6340 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006341 if (t->srv)
6342 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006343 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01006344 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02006345 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006346 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006347 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006348 if (may_dequeue_tasks(t->srv, t->proxy))
6349 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006350
willy tarreau0f7af912005-12-17 12:21:26 +01006351 return 1;
6352 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006353 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
6354 //FD_CLR(t->srv_fd, StaticWriteEvent);
6355 tv_eternity(&t->swexpire);
6356 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006357 if (t->srv)
6358 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006359 //close(t->srv_fd);
6360 t->srv_state = SV_STCLOSE;
6361 if (!(t->flags & SN_ERR_MASK))
6362 t->flags |= SN_ERR_SRVTO;
6363 if (!(t->flags & SN_FINST_MASK))
6364 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006365 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006366 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006367 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006368 if (may_dequeue_tasks(t->srv, t->proxy))
6369 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006370
willy tarreau036e1ce2005-12-17 13:46:33 +01006371 return 1;
6372 }
willy tarreau0f7af912005-12-17 12:21:26 +01006373 else if (req->l == 0) {
6374 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6375 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6376 tv_eternity(&t->swexpire);
6377 }
6378 }
6379 else { /* buffer not empty */
6380 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6381 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006382 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006383 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006384 /* FIXME: to prevent the server from expiring read timeouts during writes,
6385 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006386 t->srexpire = t->swexpire;
6387 }
willy tarreau0f7af912005-12-17 12:21:26 +01006388 else
6389 tv_eternity(&t->swexpire);
6390 }
6391 }
6392 return 0;
6393 }
6394 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006395 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006396 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01006397 tv_eternity(&t->srexpire);
6398 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006399 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006400 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006401 t->srv->failed_resp++;
6402 }
6403 t->proxy->failed_resp++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006404 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01006405 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01006406 if (!(t->flags & SN_ERR_MASK))
6407 t->flags |= SN_ERR_SRVCL;
6408 if (!(t->flags & SN_FINST_MASK))
6409 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006410 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006411 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006412 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006413 if (may_dequeue_tasks(t->srv, t->proxy))
6414 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006415
willy tarreau0f7af912005-12-17 12:21:26 +01006416 return 1;
6417 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006418 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
6419 //FD_CLR(t->srv_fd, StaticReadEvent);
6420 tv_eternity(&t->srexpire);
6421 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006422 if (t->srv)
6423 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006424 //close(t->srv_fd);
6425 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02006426 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006427 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006428 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006429 if (may_dequeue_tasks(t->srv, t->proxy))
6430 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006431
willy tarreau036e1ce2005-12-17 13:46:33 +01006432 return 1;
6433 }
6434 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6435 //FD_CLR(t->srv_fd, StaticReadEvent);
6436 tv_eternity(&t->srexpire);
6437 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006438 if (t->srv)
6439 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006440 //close(t->srv_fd);
6441 t->srv_state = SV_STCLOSE;
6442 if (!(t->flags & SN_ERR_MASK))
6443 t->flags |= SN_ERR_SRVTO;
6444 if (!(t->flags & SN_FINST_MASK))
6445 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006446 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006447 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006448 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006449 if (may_dequeue_tasks(t->srv, t->proxy))
6450 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006451
willy tarreau036e1ce2005-12-17 13:46:33 +01006452 return 1;
6453 }
willy tarreau0f7af912005-12-17 12:21:26 +01006454 else if (rep->l == BUFSIZE) { /* no room to read more data */
6455 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
6456 FD_CLR(t->srv_fd, StaticReadEvent);
6457 tv_eternity(&t->srexpire);
6458 }
6459 }
6460 else {
6461 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6462 FD_SET(t->srv_fd, StaticReadEvent);
6463 if (t->proxy->srvtimeout)
6464 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6465 else
6466 tv_eternity(&t->srexpire);
6467 }
6468 }
6469 return 0;
6470 }
6471 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01006472 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01006473 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01006474 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 +01006475 write(1, trash, len);
6476 }
6477 return 0;
6478 }
6479 return 0;
6480}
6481
6482
willy tarreau5cbea6f2005-12-17 12:48:26 +01006483/* Processes the client and server jobs of a session task, then
6484 * puts it back to the wait queue in a clean state, or
6485 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01006486 * the time the task accepts to wait, or TIME_ETERNITY for
6487 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01006488 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006489int process_session(struct task *t) {
6490 struct session *s = t->context;
6491 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006492
willy tarreau5cbea6f2005-12-17 12:48:26 +01006493 do {
6494 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01006495 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006496 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01006497 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006498 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01006499 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006500 } while (fsm_resync);
6501
6502 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01006503 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006504 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01006505
willy tarreau5cbea6f2005-12-17 12:48:26 +01006506 tv_min(&min1, &s->crexpire, &s->cwexpire);
6507 tv_min(&min2, &s->srexpire, &s->swexpire);
6508 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01006509 tv_min(&t->expire, &min1, &min2);
6510
6511 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006512 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01006513
Willy TARREAU1cec83c2006-03-01 22:33:49 +01006514#ifdef DEBUG_FULL
6515 /* DEBUG code : this should never ever happen, otherwise it indicates
6516 * that a task still has something to do and will provoke a quick loop.
6517 */
6518 if (tv_remain2(&now, &t->expire) <= 0)
6519 exit(100);
6520#endif
6521
willy tarreaub952e1d2005-12-18 01:31:20 +01006522 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01006523 }
6524
willy tarreau5cbea6f2005-12-17 12:48:26 +01006525 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01006526 actconn--;
6527
willy tarreau982249e2005-12-18 00:57:06 +01006528 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01006529 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01006530 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 +01006531 write(1, trash, len);
6532 }
6533
willy tarreau750a4722005-12-17 13:21:24 +01006534 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01006535 if (s->rep != NULL)
6536 s->logs.bytes = s->rep->total;
6537
willy tarreau9fe663a2005-12-17 13:02:59 +01006538 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01006539 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01006540 sess_log(s);
6541
willy tarreau0f7af912005-12-17 12:21:26 +01006542 /* the task MUST not be in the run queue anymore */
6543 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006544 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01006545 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01006546 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006547}
6548
6549
willy tarreau2812edc2006-05-04 12:09:37 +02006550/* Sets server <s> down, notifies by all available means, recounts the
6551 * remaining servers on the proxy and transfers queued sessions whenever
6552 * possible to other servers.
6553 */
6554void set_server_down(struct server *s) {
6555 struct pendconn *pc, *pc_bck, *pc_end;
6556 struct session *sess;
6557 int xferred;
6558
6559 s->state &= ~SRV_RUNNING;
6560
6561 if (s->health == s->rise) {
6562 recount_servers(s->proxy);
6563 recalc_server_map(s->proxy);
6564
6565 /* we might have sessions queued on this server and waiting for
6566 * a connection. Those which are redispatchable will be queued
6567 * to another server or to the proxy itself.
6568 */
6569 xferred = 0;
6570 FOREACH_ITEM_SAFE(pc, pc_bck, &s->pendconns, pc_end, struct pendconn *, list) {
6571 sess = pc->sess;
6572 if ((sess->proxy->options & PR_O_REDISP)) {
6573 /* The REDISP option was specified. We will ignore
6574 * cookie and force to balance or use the dispatcher.
6575 */
6576 sess->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
6577 sess->srv = NULL; /* it's left to the dispatcher to choose a server */
6578 if ((sess->flags & SN_CK_MASK) == SN_CK_VALID) {
6579 sess->flags &= ~SN_CK_MASK;
6580 sess->flags |= SN_CK_DOWN;
6581 }
6582 pendconn_free(pc);
6583 task_wakeup(&rq, sess->task);
6584 xferred++;
6585 }
6586 }
6587
6588 sprintf(trash, "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s"
6589 " %d sessions active, %d requeued, %d remaining in queue.\n",
6590 s->state & SRV_BACKUP ? "Backup " : "",
6591 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6592 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6593 s->cur_sess, xferred, s->nbpend);
6594
willy tarreaubc2eda62006-05-04 15:16:23 +02006595 Warning("%s", trash);
6596 send_log(s->proxy, LOG_ALERT, "%s", trash);
willy tarreau2812edc2006-05-04 12:09:37 +02006597
6598 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
6599 Alert("Proxy %s has no server available !\n", s->proxy->id);
6600 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
6601 }
willy tarreaucb406512006-05-18 00:52:35 +02006602 s->down_trans++;
willy tarreau2812edc2006-05-04 12:09:37 +02006603 }
6604 s->health = 0; /* failure */
6605}
6606
6607
willy tarreau5cbea6f2005-12-17 12:48:26 +01006608
6609/*
6610 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01006611 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01006612 */
6613int process_chk(struct task *t) {
6614 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01006615 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01006616 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006617
willy tarreauef900ab2005-12-17 12:52:52 +01006618 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006619
willy tarreau25424f82006-03-19 19:37:48 +01006620 new_chk:
6621 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006622 if (fd < 0) { /* no check currently running */
6623 //fprintf(stderr, "process_chk: 2\n");
6624 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
6625 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006626 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006627 }
Willy TARREAU3759f982006-03-01 22:44:17 +01006628
6629 /* we don't send any health-checks when the proxy is stopped or when
6630 * the server should not be checked.
6631 */
6632 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01006633 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6634 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01006635 task_queue(t); /* restore t to its place in the task list */
6636 return tv_remain2(&now, &t->expire);
6637 }
6638
willy tarreau5cbea6f2005-12-17 12:48:26 +01006639 /* we'll initiate a new check */
6640 s->result = 0; /* no result yet */
6641 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006642 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01006643 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
6644 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
6645 //fprintf(stderr, "process_chk: 3\n");
6646
willy tarreaua41a8b42005-12-17 14:02:24 +01006647 /* we'll connect to the check port on the server */
6648 sa = s->addr;
6649 sa.sin_port = htons(s->check_port);
6650
willy tarreau0174f312005-12-18 01:02:42 +01006651 /* allow specific binding :
6652 * - server-specific at first
6653 * - proxy-specific next
6654 */
6655 if (s->state & SRV_BIND_SRC) {
6656 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
6657 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
6658 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
6659 s->proxy->id, s->id);
6660 s->result = -1;
6661 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006662 }
willy tarreau0174f312005-12-18 01:02:42 +01006663 else if (s->proxy->options & PR_O_BIND_SRC) {
6664 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
6665 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
6666 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
6667 s->proxy->id);
6668 s->result = -1;
6669 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006670 }
willy tarreau0174f312005-12-18 01:02:42 +01006671
6672 if (!s->result) {
6673 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
6674 /* OK, connection in progress or established */
6675
6676 //fprintf(stderr, "process_chk: 4\n");
6677
6678 s->curfd = fd; /* that's how we know a test is in progress ;-) */
6679 fdtab[fd].owner = t;
6680 fdtab[fd].read = &event_srv_chk_r;
6681 fdtab[fd].write = &event_srv_chk_w;
6682 fdtab[fd].state = FD_STCONN; /* connection in progress */
6683 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01006684#ifdef DEBUG_FULL
6685 assert (!FD_ISSET(fd, StaticReadEvent));
6686#endif
willy tarreau0174f312005-12-18 01:02:42 +01006687 fd_insert(fd);
6688 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
6689 tv_delayfrom(&t->expire, &now, s->inter);
6690 task_queue(t); /* restore t to its place in the task list */
6691 return tv_remain(&now, &t->expire);
6692 }
6693 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
6694 s->result = -1; /* a real error */
6695 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006696 }
6697 }
willy tarreau08dedbe2005-12-18 01:13:48 +01006698 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006699 }
6700
6701 if (!s->result) { /* nothing done */
6702 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01006703 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6704 tv_delayfrom(&t->expire, &t->expire, s->inter);
6705 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006706 }
6707
6708 /* here, we have seen a failure */
willy tarreaucb406512006-05-18 00:52:35 +02006709 if (s->health > s->rise) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006710 s->health--; /* still good */
willy tarreaucb406512006-05-18 00:52:35 +02006711 s->failed_checks++;
6712 }
willy tarreau2812edc2006-05-04 12:09:37 +02006713 else
6714 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006715
6716 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01006717 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01006718 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6719 tv_delayfrom(&t->expire, &t->expire, s->inter);
6720 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006721 }
6722 else {
6723 //fprintf(stderr, "process_chk: 8\n");
6724 /* there was a test running */
6725 if (s->result > 0) { /* good server detected */
6726 //fprintf(stderr, "process_chk: 9\n");
6727 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01006728 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02006729 s->state |= SRV_RUNNING;
6730
willy tarreau535ae7a2005-12-17 12:58:00 +01006731 if (s->health == s->rise) {
willy tarreaubc2eda62006-05-04 15:16:23 +02006732 int xferred;
6733
willy tarreau62084d42006-03-24 18:57:41 +01006734 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02006735 recalc_server_map(s->proxy);
willy tarreaubc2eda62006-05-04 15:16:23 +02006736
6737 /* check if we can handle some connections queued at the proxy. We
6738 * will take as many as we can handle.
6739 */
6740 for (xferred = 0; !s->maxconn || xferred < s->maxconn; xferred++) {
6741 struct session *sess;
6742 struct pendconn *p;
6743
6744 p = pendconn_from_px(s->proxy);
6745 if (!p)
6746 break;
6747 p->sess->srv = s;
6748 sess = p->sess;
6749 pendconn_free(p);
6750 task_wakeup(&rq, sess->task);
6751 }
6752
6753 sprintf(trash,
6754 "%sServer %s/%s is UP. %d active and %d backup servers online.%s"
6755 " %d sessions requeued, %d total in queue.\n",
6756 s->state & SRV_BACKUP ? "Backup " : "",
6757 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6758 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6759 xferred, s->nbpend);
6760
6761 Warning("%s", trash);
6762 send_log(s->proxy, LOG_NOTICE, "%s", trash);
willy tarreau535ae7a2005-12-17 12:58:00 +01006763 }
willy tarreauef900ab2005-12-17 12:52:52 +01006764
willy tarreaue47c8d72005-12-17 12:55:52 +01006765 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006766 }
willy tarreauef900ab2005-12-17 12:52:52 +01006767 s->curfd = -1; /* no check running anymore */
6768 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006769 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006770 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6771 tv_delayfrom(&t->expire, &t->expire, s->inter);
6772 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006773 }
6774 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
6775 //fprintf(stderr, "process_chk: 10\n");
6776 /* failure or timeout detected */
willy tarreaucb406512006-05-18 00:52:35 +02006777 if (s->health > s->rise) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006778 s->health--; /* still good */
willy tarreaucb406512006-05-18 00:52:35 +02006779 s->failed_checks++;
6780 }
willy tarreau2812edc2006-05-04 12:09:37 +02006781 else
6782 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006783 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01006784 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006785 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006786 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6787 tv_delayfrom(&t->expire, &t->expire, s->inter);
6788 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006789 }
6790 /* if result is 0 and there's no timeout, we have to wait again */
6791 }
6792 //fprintf(stderr, "process_chk: 11\n");
6793 s->result = 0;
6794 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006795 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01006796}
6797
6798
willy tarreau5cbea6f2005-12-17 12:48:26 +01006799
willy tarreau59a6cc22006-05-12 01:29:08 +02006800/*
6801 * Manages a server's connection queue. If woken up, will try to dequeue as
6802 * many pending sessions as possible, and wake them up. The task has nothing
6803 * else to do, so it always returns TIME_ETERNITY.
6804 */
6805int process_srv_queue(struct task *t) {
6806 struct server *s = (struct server*)t->context;
6807 struct proxy *p = s->proxy;
6808 int xferred;
6809
6810 /* First, check if we can handle some connections queued at the proxy. We
6811 * will take as many as we can handle.
6812 */
6813 for (xferred = 0; s->cur_sess + xferred < s->maxconn; xferred++) {
6814 struct session *sess;
6815
6816 sess = pendconn_get_next_sess(s, p);
6817 if (sess == NULL)
6818 break;
6819 task_wakeup(&rq, sess->task);
6820 }
6821
6822 return TIME_ETERNITY;
6823}
6824
willy tarreau0f7af912005-12-17 12:21:26 +01006825#if STATTIME > 0
6826int stats(void);
6827#endif
6828
6829/*
willy tarreau1c2ad212005-12-18 01:11:29 +01006830 * This does 4 things :
6831 * - wake up all expired tasks
6832 * - call all runnable tasks
6833 * - call maintain_proxies() to enable/disable the listeners
6834 * - return the delay till next event in ms, -1 = wait indefinitely
6835 * Note: this part should be rewritten with the O(ln(n)) scheduler.
6836 *
willy tarreau0f7af912005-12-17 12:21:26 +01006837 */
6838
willy tarreau1c2ad212005-12-18 01:11:29 +01006839int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01006840 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01006841 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006842 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01006843
willy tarreaub952e1d2005-12-18 01:31:20 +01006844 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01006845
willy tarreau1c2ad212005-12-18 01:11:29 +01006846 /* look for expired tasks and add them to the run queue.
6847 */
willy tarreau5e698ef2006-05-02 14:51:00 +02006848 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6849 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau1c2ad212005-12-18 01:11:29 +01006850 tnext = t->next;
6851 if (t->state & TASK_RUNNING)
6852 continue;
6853
willy tarreaub952e1d2005-12-18 01:31:20 +01006854 if (tv_iseternity(&t->expire))
6855 continue;
6856
willy tarreau1c2ad212005-12-18 01:11:29 +01006857 /* wakeup expired entries. It doesn't matter if they are
6858 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01006859 */
willy tarreaub952e1d2005-12-18 01:31:20 +01006860 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006861 task_wakeup(&rq, t);
6862 }
6863 else {
6864 /* first non-runnable task. Use its expiration date as an upper bound */
6865 int temp_time = tv_remain(&now, &t->expire);
6866 if (temp_time)
6867 next_time = temp_time;
6868 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006869 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006870 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006871
willy tarreau1c2ad212005-12-18 01:11:29 +01006872 /* process each task in the run queue now. Each task may be deleted
willy tarreau7feab592006-04-22 15:13:16 +02006873 * since we only use the run queue's head. Note that any task can be
6874 * woken up by any other task and it will be processed immediately
6875 * after as it will be queued on the run queue's head.
willy tarreau1c2ad212005-12-18 01:11:29 +01006876 */
willy tarreau7feab592006-04-22 15:13:16 +02006877 while ((t = rq) != NULL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006878 int temp_time;
willy tarreau7feab592006-04-22 15:13:16 +02006879
willy tarreau1c2ad212005-12-18 01:11:29 +01006880 task_sleep(&rq, t);
6881 temp_time = t->process(t);
6882 next_time = MINTIME(temp_time, next_time);
6883 }
6884
6885 /* maintain all proxies in a consistent state. This should quickly become a task */
6886 time2 = maintain_proxies();
6887 return MINTIME(time2, next_time);
6888}
6889
6890
6891#if defined(ENABLE_EPOLL)
6892
6893/*
6894 * Main epoll() loop.
6895 */
6896
6897/* does 3 actions :
6898 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6899 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6900 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6901 *
6902 * returns 0 if initialization failed, !0 otherwise.
6903 */
6904
6905int epoll_loop(int action) {
6906 int next_time;
6907 int status;
6908 int fd;
6909
6910 int fds, count;
6911 int pr, pw, sr, sw;
6912 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
6913 struct epoll_event ev;
6914
6915 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01006916 static struct epoll_event *epoll_events = NULL;
6917 static int epoll_fd;
6918
6919 if (action == POLL_LOOP_ACTION_INIT) {
6920 epoll_fd = epoll_create(global.maxsock + 1);
6921 if (epoll_fd < 0)
6922 return 0;
6923 else {
6924 epoll_events = (struct epoll_event*)
6925 calloc(1, sizeof(struct epoll_event) * global.maxsock);
6926 PrevReadEvent = (fd_set *)
6927 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6928 PrevWriteEvent = (fd_set *)
6929 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006930 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006931 return 1;
6932 }
6933 else if (action == POLL_LOOP_ACTION_CLEAN) {
6934 if (PrevWriteEvent) free(PrevWriteEvent);
6935 if (PrevReadEvent) free(PrevReadEvent);
6936 if (epoll_events) free(epoll_events);
6937 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01006938 epoll_fd = 0;
6939 return 1;
6940 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006941
willy tarreau1c2ad212005-12-18 01:11:29 +01006942 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006943
willy tarreau1c2ad212005-12-18 01:11:29 +01006944 tv_now(&now);
6945
6946 while (1) {
6947 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01006948
6949 /* stop when there's no connection left and we don't allow them anymore */
6950 if (!actconn && listeners == 0)
6951 break;
6952
willy tarreau0f7af912005-12-17 12:21:26 +01006953#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01006954 {
6955 int time2;
6956 time2 = stats();
6957 next_time = MINTIME(time2, next_time);
6958 }
willy tarreau0f7af912005-12-17 12:21:26 +01006959#endif
6960
willy tarreau1c2ad212005-12-18 01:11:29 +01006961 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6962
6963 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
6964 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
6965
6966 if ((ro^rn) | (wo^wn)) {
6967 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6968#define FDSETS_ARE_INT_ALIGNED
6969#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01006970
willy tarreauad90a0c2005-12-18 01:09:15 +01006971#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6972#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01006973 pr = (ro >> count) & 1;
6974 pw = (wo >> count) & 1;
6975 sr = (rn >> count) & 1;
6976 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01006977#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006978 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
6979 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
6980 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6981 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01006982#endif
6983#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006984 pr = FD_ISSET(fd, PrevReadEvent);
6985 pw = FD_ISSET(fd, PrevWriteEvent);
6986 sr = FD_ISSET(fd, StaticReadEvent);
6987 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01006988#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01006989 if (!((sr^pr) | (sw^pw)))
6990 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01006991
willy tarreau1c2ad212005-12-18 01:11:29 +01006992 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
6993 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01006994
willy tarreaub952e1d2005-12-18 01:31:20 +01006995#ifdef EPOLL_CTL_MOD_WORKAROUND
6996 /* I encountered a rarely reproducible problem with
6997 * EPOLL_CTL_MOD where a modified FD (systematically
6998 * the one in epoll_events[0], fd#7) would sometimes
6999 * be set EPOLL_OUT while asked for a read ! This is
7000 * with the 2.4 epoll patch. The workaround is to
7001 * delete then recreate in case of modification.
7002 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
7003 * nor RHEL kernels.
7004 */
7005
7006 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
7007 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
7008
7009 if ((sr | sw))
7010 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
7011#else
willy tarreau1c2ad212005-12-18 01:11:29 +01007012 if ((pr | pw)) {
7013 /* the file-descriptor already exists... */
7014 if ((sr | sw)) {
7015 /* ...and it will still exist */
7016 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
7017 // perror("epoll_ctl(MOD)");
7018 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01007019 }
7020 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01007021 /* ...and it will be removed */
7022 if (fdtab[fd].state != FD_STCLOSE &&
7023 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
7024 // perror("epoll_ctl(DEL)");
7025 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01007026 }
7027 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007028 } else {
7029 /* the file-descriptor did not exist, let's add it */
7030 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
7031 // perror("epoll_ctl(ADD)");
7032 // exit(1);
7033 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007034 }
willy tarreaub952e1d2005-12-18 01:31:20 +01007035#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01007036 }
7037 ((int*)PrevReadEvent)[fds] = rn;
7038 ((int*)PrevWriteEvent)[fds] = wn;
7039 }
7040 }
7041
7042 /* now let's wait for events */
7043 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
7044 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01007045
willy tarreau1c2ad212005-12-18 01:11:29 +01007046 for (count = 0; count < status; count++) {
7047 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01007048
7049 if (FD_ISSET(fd, StaticReadEvent)) {
7050 if (fdtab[fd].state == FD_STCLOSE)
7051 continue;
7052 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
7053 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007054 }
willy tarreau05be12b2006-03-19 19:35:00 +01007055
7056 if (FD_ISSET(fd, StaticWriteEvent)) {
7057 if (fdtab[fd].state == FD_STCLOSE)
7058 continue;
7059 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
7060 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007061 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007062 }
7063 }
7064 return 1;
7065}
7066#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01007067
willy tarreauad90a0c2005-12-18 01:09:15 +01007068
willy tarreau5cbea6f2005-12-17 12:48:26 +01007069
willy tarreau1c2ad212005-12-18 01:11:29 +01007070#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01007071
willy tarreau1c2ad212005-12-18 01:11:29 +01007072/*
7073 * Main poll() loop.
7074 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007075
willy tarreau1c2ad212005-12-18 01:11:29 +01007076/* does 3 actions :
7077 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
7078 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
7079 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
7080 *
7081 * returns 0 if initialization failed, !0 otherwise.
7082 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007083
willy tarreau1c2ad212005-12-18 01:11:29 +01007084int poll_loop(int action) {
7085 int next_time;
7086 int status;
7087 int fd, nbfd;
7088
7089 int fds, count;
7090 int sr, sw;
7091 unsigned rn, wn; /* read new, write new */
7092
7093 /* private data */
7094 static struct pollfd *poll_events = NULL;
7095
7096 if (action == POLL_LOOP_ACTION_INIT) {
7097 poll_events = (struct pollfd*)
7098 calloc(1, sizeof(struct pollfd) * global.maxsock);
7099 return 1;
7100 }
7101 else if (action == POLL_LOOP_ACTION_CLEAN) {
7102 if (poll_events)
7103 free(poll_events);
7104 return 1;
7105 }
7106
7107 /* OK, it's POLL_LOOP_ACTION_RUN */
7108
7109 tv_now(&now);
7110
7111 while (1) {
7112 next_time = process_runnable_tasks();
7113
7114 /* stop when there's no connection left and we don't allow them anymore */
7115 if (!actconn && listeners == 0)
7116 break;
7117
7118#if STATTIME > 0
7119 {
7120 int time2;
7121 time2 = stats();
7122 next_time = MINTIME(time2, next_time);
7123 }
7124#endif
7125
7126
7127 nbfd = 0;
7128 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
7129
7130 rn = ((int*)StaticReadEvent)[fds];
7131 wn = ((int*)StaticWriteEvent)[fds];
7132
7133 if ((rn|wn)) {
7134 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
7135#define FDSETS_ARE_INT_ALIGNED
7136#ifdef FDSETS_ARE_INT_ALIGNED
7137
7138#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
7139#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
7140 sr = (rn >> count) & 1;
7141 sw = (wn >> count) & 1;
7142#else
7143 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
7144 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
7145#endif
7146#else
7147 sr = FD_ISSET(fd, StaticReadEvent);
7148 sw = FD_ISSET(fd, StaticWriteEvent);
7149#endif
7150 if ((sr|sw)) {
7151 poll_events[nbfd].fd = fd;
7152 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
7153 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01007154 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007155 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007156 }
7157 }
7158
7159 /* now let's wait for events */
7160 status = poll(poll_events, nbfd, next_time);
7161 tv_now(&now);
7162
7163 for (count = 0; status > 0 && count < nbfd; count++) {
7164 fd = poll_events[count].fd;
7165
willy tarreau606788e2006-05-21 16:26:20 +02007166 if (!(poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP )))
willy tarreau1c2ad212005-12-18 01:11:29 +01007167 continue;
7168
7169 /* ok, we found one active fd */
7170 status--;
7171
willy tarreau05be12b2006-03-19 19:35:00 +01007172 if (FD_ISSET(fd, StaticReadEvent)) {
7173 if (fdtab[fd].state == FD_STCLOSE)
7174 continue;
7175 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
7176 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007177 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007178
willy tarreau05be12b2006-03-19 19:35:00 +01007179 if (FD_ISSET(fd, StaticWriteEvent)) {
7180 if (fdtab[fd].state == FD_STCLOSE)
7181 continue;
7182 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
7183 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007184 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007185 }
7186 }
7187 return 1;
7188}
willy tarreauad90a0c2005-12-18 01:09:15 +01007189#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01007190
willy tarreauad90a0c2005-12-18 01:09:15 +01007191
willy tarreauad90a0c2005-12-18 01:09:15 +01007192
willy tarreau1c2ad212005-12-18 01:11:29 +01007193/*
7194 * Main select() loop.
7195 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007196
willy tarreau1c2ad212005-12-18 01:11:29 +01007197/* does 3 actions :
7198 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
7199 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
7200 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
7201 *
7202 * returns 0 if initialization failed, !0 otherwise.
7203 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007204
willy tarreauad90a0c2005-12-18 01:09:15 +01007205
willy tarreau1c2ad212005-12-18 01:11:29 +01007206int select_loop(int action) {
7207 int next_time;
7208 int status;
7209 int fd,i;
7210 struct timeval delta;
7211 int readnotnull, writenotnull;
7212 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01007213
willy tarreau1c2ad212005-12-18 01:11:29 +01007214 if (action == POLL_LOOP_ACTION_INIT) {
7215 ReadEvent = (fd_set *)
7216 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
7217 WriteEvent = (fd_set *)
7218 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
7219 return 1;
7220 }
7221 else if (action == POLL_LOOP_ACTION_CLEAN) {
7222 if (WriteEvent) free(WriteEvent);
7223 if (ReadEvent) free(ReadEvent);
7224 return 1;
7225 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007226
willy tarreau1c2ad212005-12-18 01:11:29 +01007227 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01007228
willy tarreau1c2ad212005-12-18 01:11:29 +01007229 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01007230
willy tarreau1c2ad212005-12-18 01:11:29 +01007231 while (1) {
7232 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01007233
willy tarreau1c2ad212005-12-18 01:11:29 +01007234 /* stop when there's no connection left and we don't allow them anymore */
7235 if (!actconn && listeners == 0)
7236 break;
7237
7238#if STATTIME > 0
7239 {
7240 int time2;
7241 time2 = stats();
7242 next_time = MINTIME(time2, next_time);
7243 }
7244#endif
7245
willy tarreau1c2ad212005-12-18 01:11:29 +01007246 if (next_time > 0) { /* FIXME */
7247 /* Convert to timeval */
7248 /* to avoid eventual select loops due to timer precision */
7249 next_time += SCHEDULER_RESOLUTION;
7250 delta.tv_sec = next_time / 1000;
7251 delta.tv_usec = (next_time % 1000) * 1000;
7252 }
7253 else if (next_time == 0) { /* allow select to return immediately when needed */
7254 delta.tv_sec = delta.tv_usec = 0;
7255 }
7256
7257
7258 /* let's restore fdset state */
7259
7260 readnotnull = 0; writenotnull = 0;
7261 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
7262 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
7263 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
7264 }
7265
7266 // /* just a verification code, needs to be removed for performance */
7267 // for (i=0; i<maxfd; i++) {
7268 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
7269 // abort();
7270 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
7271 // abort();
7272 //
7273 // }
7274
7275 status = select(maxfd,
7276 readnotnull ? ReadEvent : NULL,
7277 writenotnull ? WriteEvent : NULL,
7278 NULL,
7279 (next_time >= 0) ? &delta : NULL);
7280
7281 /* this is an experiment on the separation of the select work */
7282 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
7283 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
7284
7285 tv_now(&now);
7286
7287 if (status > 0) { /* must proceed with events */
7288
7289 int fds;
7290 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01007291
willy tarreau1c2ad212005-12-18 01:11:29 +01007292 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
7293 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
7294 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
7295
7296 /* if we specify read first, the accepts and zero reads will be
7297 * seen first. Moreover, system buffers will be flushed faster.
7298 */
willy tarreau05be12b2006-03-19 19:35:00 +01007299 if (FD_ISSET(fd, ReadEvent)) {
7300 if (fdtab[fd].state == FD_STCLOSE)
7301 continue;
7302 fdtab[fd].read(fd);
7303 }
willy tarreau64a3cc32005-12-18 01:13:11 +01007304
willy tarreau05be12b2006-03-19 19:35:00 +01007305 if (FD_ISSET(fd, WriteEvent)) {
7306 if (fdtab[fd].state == FD_STCLOSE)
7307 continue;
7308 fdtab[fd].write(fd);
7309 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007310 }
7311 }
7312 else {
7313 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01007314 }
willy tarreau0f7af912005-12-17 12:21:26 +01007315 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007316 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01007317}
7318
7319
7320#if STATTIME > 0
7321/*
7322 * Display proxy statistics regularly. It is designed to be called from the
7323 * select_loop().
7324 */
7325int stats(void) {
7326 static int lines;
7327 static struct timeval nextevt;
7328 static struct timeval lastevt;
7329 static struct timeval starttime = {0,0};
7330 unsigned long totaltime, deltatime;
7331 int ret;
7332
willy tarreau750a4722005-12-17 13:21:24 +01007333 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01007334 deltatime = (tv_diff(&lastevt, &now)?:1);
7335 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01007336
willy tarreau9fe663a2005-12-17 13:02:59 +01007337 if (global.mode & MODE_STATS) {
7338 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007339 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007340 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
7341 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007342 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01007343 actconn, totalconn,
7344 stats_tsk_new, stats_tsk_good,
7345 stats_tsk_left, stats_tsk_right,
7346 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
7347 }
7348 }
7349
7350 tv_delayfrom(&nextevt, &now, STATTIME);
7351
7352 lastevt=now;
7353 }
7354 ret = tv_remain(&now, &nextevt);
7355 return ret;
7356}
7357#endif
7358
7359
7360/*
7361 * this function enables proxies when there are enough free sessions,
7362 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01007363 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01007364 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01007365 */
7366static int maintain_proxies(void) {
7367 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01007368 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007369 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01007370
7371 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01007372 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01007373
7374 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01007375 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01007376 while (p) {
7377 if (p->nbconn < p->maxconn) {
7378 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007379 for (l = p->listen; l != NULL; l = l->next) {
7380 FD_SET(l->fd, StaticReadEvent);
7381 }
willy tarreau0f7af912005-12-17 12:21:26 +01007382 p->state = PR_STRUN;
7383 }
7384 }
7385 else {
7386 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007387 for (l = p->listen; l != NULL; l = l->next) {
7388 FD_CLR(l->fd, StaticReadEvent);
7389 }
willy tarreau0f7af912005-12-17 12:21:26 +01007390 p->state = PR_STIDLE;
7391 }
7392 }
7393 p = p->next;
7394 }
7395 }
7396 else { /* block all proxies */
7397 while (p) {
7398 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007399 for (l = p->listen; l != NULL; l = l->next) {
7400 FD_CLR(l->fd, StaticReadEvent);
7401 }
willy tarreau0f7af912005-12-17 12:21:26 +01007402 p->state = PR_STIDLE;
7403 }
7404 p = p->next;
7405 }
7406 }
7407
willy tarreau5cbea6f2005-12-17 12:48:26 +01007408 if (stopping) {
7409 p = proxy;
7410 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007411 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007412 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01007413 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007414 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01007415 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01007416 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01007417
willy tarreaua41a8b42005-12-17 14:02:24 +01007418 for (l = p->listen; l != NULL; l = l->next) {
7419 fd_delete(l->fd);
7420 listeners--;
7421 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007422 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007423 }
7424 else {
7425 tleft = MINTIME(t, tleft);
7426 }
7427 }
7428 p = p->next;
7429 }
7430 }
7431 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01007432}
7433
7434/*
7435 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01007436 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
7437 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01007438 */
7439static void soft_stop(void) {
7440 struct proxy *p;
7441
7442 stopping = 1;
7443 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007444 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01007445 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01007446 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01007447 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01007448 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01007449 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01007450 }
willy tarreau0f7af912005-12-17 12:21:26 +01007451 p = p->next;
7452 }
7453}
7454
willy tarreaufac1a862006-05-21 10:20:28 +02007455/*
7456 * Linux unbinds the listen socket after a SHUT_RD, and ignores SHUT_WR.
7457 * Solaris refuses either shutdown().
7458 * OpenBSD ignores SHUT_RD but closes upon SHUT_WR and refuses to rebind.
7459 * So a common validation path involves SHUT_WR && listen && SHUT_RD.
7460 * If disabling at least one listener returns an error, then the proxy
7461 * state is set to PR_STERROR because we don't know how to resume from this.
7462 */
willy tarreaudbd3bef2006-01-20 19:35:18 +01007463static void pause_proxy(struct proxy *p) {
7464 struct listener *l;
7465 for (l = p->listen; l != NULL; l = l->next) {
willy tarreaufac1a862006-05-21 10:20:28 +02007466 if (shutdown(l->fd, SHUT_WR) == 0 && listen(l->fd, p->maxconn) == 0 &&
7467 shutdown(l->fd, SHUT_RD) == 0) {
Willy TARREAU007aa462006-05-14 09:55:23 +02007468 FD_CLR(l->fd, StaticReadEvent);
willy tarreaufac1a862006-05-21 10:20:28 +02007469 if (p->state != PR_STERROR)
7470 p->state = PR_STPAUSED;
Willy TARREAU007aa462006-05-14 09:55:23 +02007471 }
willy tarreaufac1a862006-05-21 10:20:28 +02007472 else
7473 p->state = PR_STERROR;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007474 }
7475}
7476
7477/*
7478 * This function temporarily disables listening so that another new instance
7479 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01007480 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01007481 * the proxy, or a SIGTTIN can be sent to listen again.
7482 */
7483static void pause_proxies(void) {
Willy TARREAU007aa462006-05-14 09:55:23 +02007484 int err;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007485 struct proxy *p;
7486
Willy TARREAU007aa462006-05-14 09:55:23 +02007487 err = 0;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007488 p = proxy;
7489 tv_now(&now); /* else, the old time before select will be used */
7490 while (p) {
willy tarreaufac1a862006-05-21 10:20:28 +02007491 if (p->state != PR_STERROR && p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007492 Warning("Pausing proxy %s.\n", p->id);
7493 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
7494 pause_proxy(p);
Willy TARREAU007aa462006-05-14 09:55:23 +02007495 if (p->state != PR_STPAUSED) {
7496 err |= 1;
7497 Warning("Proxy %s failed to enter pause mode.\n", p->id);
7498 send_log(p, LOG_WARNING, "Proxy %s failed to enter pause mode.\n", p->id);
7499 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007500 }
7501 p = p->next;
7502 }
Willy TARREAU007aa462006-05-14 09:55:23 +02007503 if (err) {
7504 Warning("Some proxies refused to pause, performing soft stop now.\n");
7505 send_log(p, LOG_WARNING, "Some proxies refused to pause, performing soft stop now.\n");
7506 soft_stop();
7507 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007508}
7509
7510
7511/*
7512 * This function reactivates listening. This can be used after a call to
7513 * sig_pause(), for example when a new instance has failed starting up.
7514 * It is designed to be called upon reception of a SIGTTIN.
7515 */
7516static void listen_proxies(void) {
7517 struct proxy *p;
7518 struct listener *l;
7519
7520 p = proxy;
7521 tv_now(&now); /* else, the old time before select will be used */
7522 while (p) {
7523 if (p->state == PR_STPAUSED) {
7524 Warning("Enabling proxy %s.\n", p->id);
7525 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
7526
7527 for (l = p->listen; l != NULL; l = l->next) {
7528 if (listen(l->fd, p->maxconn) == 0) {
7529 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
7530 FD_SET(l->fd, StaticReadEvent);
7531 p->state = PR_STRUN;
7532 }
7533 else
7534 p->state = PR_STIDLE;
7535 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01007536 int port;
7537
7538 if (l->addr.ss_family == AF_INET6)
7539 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
7540 else
7541 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
7542
willy tarreaudbd3bef2006-01-20 19:35:18 +01007543 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01007544 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01007545 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01007546 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01007547 /* Another port might have been enabled. Let's stop everything. */
7548 pause_proxy(p);
7549 break;
7550 }
7551 }
7552 }
7553 p = p->next;
7554 }
7555}
7556
7557
willy tarreau0f7af912005-12-17 12:21:26 +01007558/*
7559 * upon SIGUSR1, let's have a soft stop.
7560 */
7561void sig_soft_stop(int sig) {
7562 soft_stop();
7563 signal(sig, SIG_IGN);
7564}
7565
willy tarreaudbd3bef2006-01-20 19:35:18 +01007566/*
7567 * upon SIGTTOU, we pause everything
7568 */
7569void sig_pause(int sig) {
7570 pause_proxies();
7571 signal(sig, sig_pause);
7572}
willy tarreau0f7af912005-12-17 12:21:26 +01007573
willy tarreau8337c6b2005-12-17 13:41:01 +01007574/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01007575 * upon SIGTTIN, let's have a soft stop.
7576 */
7577void sig_listen(int sig) {
7578 listen_proxies();
7579 signal(sig, sig_listen);
7580}
7581
7582/*
willy tarreau8337c6b2005-12-17 13:41:01 +01007583 * this function dumps every server's state when the process receives SIGHUP.
7584 */
7585void sig_dump_state(int sig) {
7586 struct proxy *p = proxy;
7587
7588 Warning("SIGHUP received, dumping servers states.\n");
7589 while (p) {
7590 struct server *s = p->srv;
7591
willy tarreau4632c212006-05-02 23:32:51 +02007592 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01007593 while (s) {
willy tarreau4632c212006-05-02 23:32:51 +02007594 snprintf(trash, sizeof(trash),
7595 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %d tot.",
7596 p->id, s->id,
7597 (s->state & SRV_RUNNING) ? "UP" : "DOWN",
7598 s->cur_sess, s->nbpend, s->cum_sess);
willy tarreau14b4d432006-04-07 18:23:29 +02007599 Warning("%s\n", trash);
7600 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01007601 s = s->next;
7602 }
willy tarreaudd07e972005-12-18 00:48:48 +01007603
willy tarreau62084d42006-03-24 18:57:41 +01007604 if (p->srv_act == 0) {
willy tarreau4632c212006-05-02 23:32:51 +02007605 snprintf(trash, sizeof(trash),
7606 "SIGHUP: Proxy %s %s ! Conn: %d act, %d pend (%d unass), %d tot.",
7607 p->id,
7608 (p->srv_bck) ? "is running on backup servers" : "has no server available",
7609 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02007610 } else {
7611 snprintf(trash, sizeof(trash),
willy tarreau4632c212006-05-02 23:32:51 +02007612 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
7613 " Conn: %d act, %d pend (%d unass), %d tot.",
7614 p->id, p->srv_act, p->srv_bck,
7615 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02007616 }
7617 Warning("%s\n", trash);
7618 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01007619
willy tarreau8337c6b2005-12-17 13:41:01 +01007620 p = p->next;
7621 }
7622 signal(sig, sig_dump_state);
7623}
7624
willy tarreau0f7af912005-12-17 12:21:26 +01007625void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007626 struct task *t, *tnext;
7627 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01007628
willy tarreau5e698ef2006-05-02 14:51:00 +02007629 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
7630 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007631 tnext = t->next;
7632 s = t->context;
7633 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
7634 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
7635 "req=%d, rep=%d, clifd=%d\n",
7636 s, tv_remain(&now, &t->expire),
7637 s->cli_state,
7638 s->srv_state,
7639 FD_ISSET(s->cli_fd, StaticReadEvent),
7640 FD_ISSET(s->cli_fd, StaticWriteEvent),
7641 FD_ISSET(s->srv_fd, StaticReadEvent),
7642 FD_ISSET(s->srv_fd, StaticWriteEvent),
7643 s->req->l, s->rep?s->rep->l:0, s->cli_fd
7644 );
willy tarreau0f7af912005-12-17 12:21:26 +01007645 }
willy tarreau12350152005-12-18 01:03:27 +01007646}
7647
willy tarreau64a3cc32005-12-18 01:13:11 +01007648#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01007649static void fast_stop(void)
7650{
7651 struct proxy *p;
7652 p = proxy;
7653 while (p) {
7654 p->grace = 0;
7655 p = p->next;
7656 }
7657 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01007658}
7659
willy tarreau12350152005-12-18 01:03:27 +01007660void sig_int(int sig) {
7661 /* This would normally be a hard stop,
7662 but we want to be sure about deallocation,
7663 and so on, so we do a soft stop with
7664 0 GRACE time
7665 */
7666 fast_stop();
7667 /* If we are killed twice, we decide to die*/
7668 signal(sig, SIG_DFL);
7669}
7670
7671void sig_term(int sig) {
7672 /* This would normally be a hard stop,
7673 but we want to be sure about deallocation,
7674 and so on, so we do a soft stop with
7675 0 GRACE time
7676 */
7677 fast_stop();
7678 /* If we are killed twice, we decide to die*/
7679 signal(sig, SIG_DFL);
7680}
willy tarreau64a3cc32005-12-18 01:13:11 +01007681#endif
willy tarreau12350152005-12-18 01:03:27 +01007682
willy tarreauc1f47532005-12-18 01:08:26 +01007683/* returns the pointer to an error in the replacement string, or NULL if OK */
7684char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01007685 struct hdr_exp *exp;
7686
willy tarreauc1f47532005-12-18 01:08:26 +01007687 if (replace != NULL) {
7688 char *err;
7689 err = check_replace_string(replace);
7690 if (err)
7691 return err;
7692 }
7693
willy tarreaue39cd132005-12-17 13:00:18 +01007694 while (*head != NULL)
7695 head = &(*head)->next;
7696
7697 exp = calloc(1, sizeof(struct hdr_exp));
7698
7699 exp->preg = preg;
7700 exp->replace = replace;
7701 exp->action = action;
7702 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01007703
7704 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007705}
7706
willy tarreau9fe663a2005-12-17 13:02:59 +01007707
willy tarreau0f7af912005-12-17 12:21:26 +01007708/*
willy tarreau9fe663a2005-12-17 13:02:59 +01007709 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01007710 */
willy tarreau9fe663a2005-12-17 13:02:59 +01007711int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01007712
willy tarreau9fe663a2005-12-17 13:02:59 +01007713 if (!strcmp(args[0], "global")) { /* new section */
7714 /* no option, nothing special to do */
7715 return 0;
7716 }
7717 else if (!strcmp(args[0], "daemon")) {
7718 global.mode |= MODE_DAEMON;
7719 }
7720 else if (!strcmp(args[0], "debug")) {
7721 global.mode |= MODE_DEBUG;
7722 }
willy tarreau64a3cc32005-12-18 01:13:11 +01007723 else if (!strcmp(args[0], "noepoll")) {
7724 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
7725 }
7726 else if (!strcmp(args[0], "nopoll")) {
7727 cfg_polling_mechanism &= ~POLL_USE_POLL;
7728 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007729 else if (!strcmp(args[0], "quiet")) {
7730 global.mode |= MODE_QUIET;
7731 }
7732 else if (!strcmp(args[0], "stats")) {
7733 global.mode |= MODE_STATS;
7734 }
7735 else if (!strcmp(args[0], "uid")) {
7736 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007737 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007738 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007739 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007740 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007741 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007742 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007743 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007744 global.uid = atol(args[1]);
7745 }
7746 else if (!strcmp(args[0], "gid")) {
7747 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007748 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007749 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007750 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007751 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007752 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007753 return -1;
7754 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007755 global.gid = atol(args[1]);
7756 }
7757 else if (!strcmp(args[0], "nbproc")) {
7758 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007759 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007760 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007761 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007762 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007763 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007764 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007765 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007766 global.nbproc = atol(args[1]);
7767 }
7768 else if (!strcmp(args[0], "maxconn")) {
7769 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007770 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007771 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007772 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007773 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007774 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007775 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007776 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007777 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01007778#ifdef SYSTEM_MAXCONN
7779 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
7780 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);
7781 global.maxconn = DEFAULT_MAXCONN;
7782 }
7783#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01007784 }
willy tarreaub1285d52005-12-18 01:20:14 +01007785 else if (!strcmp(args[0], "ulimit-n")) {
7786 if (global.rlimit_nofile != 0) {
7787 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7788 return 0;
7789 }
7790 if (*(args[1]) == 0) {
7791 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
7792 return -1;
7793 }
7794 global.rlimit_nofile = atol(args[1]);
7795 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007796 else if (!strcmp(args[0], "chroot")) {
7797 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007798 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007799 return 0;
7800 }
7801 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007802 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007803 return -1;
7804 }
7805 global.chroot = strdup(args[1]);
7806 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007807 else if (!strcmp(args[0], "pidfile")) {
7808 if (global.pidfile != NULL) {
7809 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7810 return 0;
7811 }
7812 if (*(args[1]) == 0) {
7813 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
7814 return -1;
7815 }
7816 global.pidfile = strdup(args[1]);
7817 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007818 else if (!strcmp(args[0], "log")) { /* syslog server address */
7819 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01007820 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007821
7822 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007823 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007824 return -1;
7825 }
7826
7827 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7828 if (!strcmp(log_facilities[facility], args[2]))
7829 break;
7830
7831 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007832 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007833 exit(1);
7834 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007835
7836 level = 7; /* max syslog level = debug */
7837 if (*(args[3])) {
7838 while (level >= 0 && strcmp(log_levels[level], args[3]))
7839 level--;
7840 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007841 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007842 exit(1);
7843 }
7844 }
7845
willy tarreau9fe663a2005-12-17 13:02:59 +01007846 sa = str2sa(args[1]);
7847 if (!sa->sin_port)
7848 sa->sin_port = htons(SYSLOG_PORT);
7849
7850 if (global.logfac1 == -1) {
7851 global.logsrv1 = *sa;
7852 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007853 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007854 }
7855 else if (global.logfac2 == -1) {
7856 global.logsrv2 = *sa;
7857 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007858 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007859 }
7860 else {
7861 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
7862 return -1;
7863 }
7864
7865 }
7866 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007867 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01007868 return -1;
7869 }
7870 return 0;
7871}
7872
7873
willy tarreaua41a8b42005-12-17 14:02:24 +01007874void init_default_instance() {
7875 memset(&defproxy, 0, sizeof(defproxy));
7876 defproxy.mode = PR_MODE_TCP;
7877 defproxy.state = PR_STNEW;
7878 defproxy.maxconn = cfg_maxpconn;
7879 defproxy.conn_retries = CONN_RETRIES;
7880 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
7881}
7882
willy tarreau9fe663a2005-12-17 13:02:59 +01007883/*
7884 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
7885 */
7886int cfg_parse_listen(char *file, int linenum, char **args) {
7887 static struct proxy *curproxy = NULL;
7888 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01007889 char *err;
willy tarreau12350152005-12-18 01:03:27 +01007890 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01007891
7892 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01007893 if (!*args[1]) {
7894 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
7895 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007896 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007897 return -1;
7898 }
7899
7900 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007901 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007902 return -1;
7903 }
willy tarreaudfece232006-05-02 00:19:57 +02007904
willy tarreau9fe663a2005-12-17 13:02:59 +01007905 curproxy->next = proxy;
7906 proxy = curproxy;
willy tarreaudfece232006-05-02 00:19:57 +02007907 LIST_INIT(&curproxy->pendconns);
7908
willy tarreau9fe663a2005-12-17 13:02:59 +01007909 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01007910
7911 /* parse the listener address if any */
7912 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007913 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007914 if (!curproxy->listen)
7915 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007916 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01007917 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007918
willy tarreau9fe663a2005-12-17 13:02:59 +01007919 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01007920 curproxy->state = defproxy.state;
7921 curproxy->maxconn = defproxy.maxconn;
7922 curproxy->conn_retries = defproxy.conn_retries;
7923 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007924
7925 if (defproxy.check_req)
7926 curproxy->check_req = strdup(defproxy.check_req);
7927 curproxy->check_len = defproxy.check_len;
7928
7929 if (defproxy.cookie_name)
7930 curproxy->cookie_name = strdup(defproxy.cookie_name);
7931 curproxy->cookie_len = defproxy.cookie_len;
7932
7933 if (defproxy.capture_name)
7934 curproxy->capture_name = strdup(defproxy.capture_name);
7935 curproxy->capture_namelen = defproxy.capture_namelen;
7936 curproxy->capture_len = defproxy.capture_len;
7937
7938 if (defproxy.errmsg.msg400)
7939 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
7940 curproxy->errmsg.len400 = defproxy.errmsg.len400;
7941
7942 if (defproxy.errmsg.msg403)
7943 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
7944 curproxy->errmsg.len403 = defproxy.errmsg.len403;
7945
7946 if (defproxy.errmsg.msg408)
7947 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
7948 curproxy->errmsg.len408 = defproxy.errmsg.len408;
7949
7950 if (defproxy.errmsg.msg500)
7951 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
7952 curproxy->errmsg.len500 = defproxy.errmsg.len500;
7953
7954 if (defproxy.errmsg.msg502)
7955 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
7956 curproxy->errmsg.len502 = defproxy.errmsg.len502;
7957
7958 if (defproxy.errmsg.msg503)
7959 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
7960 curproxy->errmsg.len503 = defproxy.errmsg.len503;
7961
7962 if (defproxy.errmsg.msg504)
7963 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
7964 curproxy->errmsg.len504 = defproxy.errmsg.len504;
7965
willy tarreaua41a8b42005-12-17 14:02:24 +01007966 curproxy->clitimeout = defproxy.clitimeout;
7967 curproxy->contimeout = defproxy.contimeout;
7968 curproxy->srvtimeout = defproxy.srvtimeout;
7969 curproxy->mode = defproxy.mode;
7970 curproxy->logfac1 = defproxy.logfac1;
7971 curproxy->logsrv1 = defproxy.logsrv1;
7972 curproxy->loglev1 = defproxy.loglev1;
7973 curproxy->logfac2 = defproxy.logfac2;
7974 curproxy->logsrv2 = defproxy.logsrv2;
7975 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01007976 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01007977 curproxy->grace = defproxy.grace;
willy tarreau1f431b52006-05-21 14:46:15 +02007978 curproxy->uri_auth = defproxy.uri_auth;
willy tarreaua41a8b42005-12-17 14:02:24 +01007979 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01007980 curproxy->mon_net = defproxy.mon_net;
7981 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01007982 return 0;
7983 }
7984 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007985 /* some variables may have already been initialized earlier */
7986 if (defproxy.check_req) free(defproxy.check_req);
7987 if (defproxy.cookie_name) free(defproxy.cookie_name);
7988 if (defproxy.capture_name) free(defproxy.capture_name);
7989 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
7990 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
7991 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
7992 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
7993 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
7994 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
7995 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
willy tarreau1f431b52006-05-21 14:46:15 +02007996 /* we cannot free uri_auth because it might already be used */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007997 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01007998 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01007999 return 0;
8000 }
8001 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008002 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01008003 return -1;
8004 }
8005
willy tarreaua41a8b42005-12-17 14:02:24 +01008006 if (!strcmp(args[0], "bind")) { /* new listen addresses */
8007 if (curproxy == &defproxy) {
8008 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8009 return -1;
8010 }
8011
8012 if (strchr(args[1], ':') == NULL) {
8013 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
8014 file, linenum, args[0]);
8015 return -1;
8016 }
8017 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01008018 if (!curproxy->listen)
8019 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008020 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01008021 return 0;
8022 }
willy tarreaub1285d52005-12-18 01:20:14 +01008023 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
8024 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
8025 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
8026 file, linenum, args[0]);
8027 return -1;
8028 }
8029 /* flush useless bits */
8030 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
8031 return 0;
8032 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008033 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01008034 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
8035 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
8036 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
8037 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008038 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008039 return -1;
8040 }
8041 }
8042 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01008043 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01008044 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008045 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
8046 curproxy->state = PR_STNEW;
8047 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008048 else if (!strcmp(args[0], "cookie")) { /* cookie name */
8049 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01008050// if (curproxy == &defproxy) {
8051// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8052// return -1;
8053// }
willy tarreaua41a8b42005-12-17 14:02:24 +01008054
willy tarreau9fe663a2005-12-17 13:02:59 +01008055 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008056// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
8057// file, linenum);
8058// return 0;
8059 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01008060 }
8061
8062 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008063 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
8064 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008065 return -1;
8066 }
8067 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008068 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01008069
8070 cur_arg = 2;
8071 while (*(args[cur_arg])) {
8072 if (!strcmp(args[cur_arg], "rewrite")) {
8073 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01008074 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008075 else if (!strcmp(args[cur_arg], "indirect")) {
8076 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01008077 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008078 else if (!strcmp(args[cur_arg], "insert")) {
8079 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01008080 }
willy tarreau240afa62005-12-17 13:14:35 +01008081 else if (!strcmp(args[cur_arg], "nocache")) {
8082 curproxy->options |= PR_O_COOK_NOC;
8083 }
willy tarreaucd878942005-12-17 13:27:43 +01008084 else if (!strcmp(args[cur_arg], "postonly")) {
8085 curproxy->options |= PR_O_COOK_POST;
8086 }
willy tarreau0174f312005-12-18 01:02:42 +01008087 else if (!strcmp(args[cur_arg], "prefix")) {
8088 curproxy->options |= PR_O_COOK_PFX;
8089 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008090 else {
willy tarreau0174f312005-12-18 01:02:42 +01008091 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008092 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01008093 return -1;
8094 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008095 cur_arg++;
8096 }
willy tarreau0174f312005-12-18 01:02:42 +01008097 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
8098 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
8099 file, linenum);
8100 return -1;
8101 }
8102
8103 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
8104 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01008105 file, linenum);
8106 return -1;
8107 }
willy tarreau12350152005-12-18 01:03:27 +01008108 }/* end else if (!strcmp(args[0], "cookie")) */
8109 else if (!strcmp(args[0], "appsession")) { /* cookie name */
8110// if (curproxy == &defproxy) {
8111// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8112// return -1;
8113// }
8114
8115 if (curproxy->appsession_name != NULL) {
8116// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
8117// file, linenum);
8118// return 0;
8119 free(curproxy->appsession_name);
8120 }
8121
8122 if (*(args[5]) == 0) {
8123 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
8124 file, linenum, args[0]);
8125 return -1;
8126 }
8127 have_appsession = 1;
8128 curproxy->appsession_name = strdup(args[1]);
8129 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
8130 curproxy->appsession_len = atoi(args[3]);
8131 curproxy->appsession_timeout = atoi(args[5]);
8132 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
8133 if (rc) {
8134 Alert("Error Init Appsession Hashtable.\n");
8135 return -1;
8136 }
8137 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01008138 else if (!strcmp(args[0], "capture")) {
8139 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
8140 // if (curproxy == &defproxy) {
8141 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8142 // return -1;
8143 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01008144
willy tarreau4302f492005-12-18 01:00:37 +01008145 if (curproxy->capture_name != NULL) {
8146 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
8147 // file, linenum, args[0]);
8148 // return 0;
8149 free(curproxy->capture_name);
8150 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008151
willy tarreau4302f492005-12-18 01:00:37 +01008152 if (*(args[4]) == 0) {
8153 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
8154 file, linenum, args[0]);
8155 return -1;
8156 }
8157 curproxy->capture_name = strdup(args[2]);
8158 curproxy->capture_namelen = strlen(curproxy->capture_name);
8159 curproxy->capture_len = atol(args[4]);
8160 if (curproxy->capture_len >= CAPTURE_LEN) {
8161 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
8162 file, linenum, CAPTURE_LEN - 1);
8163 curproxy->capture_len = CAPTURE_LEN - 1;
8164 }
8165 curproxy->to_log |= LW_COOKIE;
8166 }
8167 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
8168 struct cap_hdr *hdr;
8169
8170 if (curproxy == &defproxy) {
8171 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
8172 return -1;
8173 }
8174
8175 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
8176 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
8177 file, linenum, args[0], args[1]);
8178 return -1;
8179 }
8180
8181 hdr = calloc(sizeof(struct cap_hdr), 1);
8182 hdr->next = curproxy->req_cap;
8183 hdr->name = strdup(args[3]);
8184 hdr->namelen = strlen(args[3]);
8185 hdr->len = atol(args[5]);
8186 hdr->index = curproxy->nb_req_cap++;
8187 curproxy->req_cap = hdr;
8188 curproxy->to_log |= LW_REQHDR;
8189 }
8190 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
8191 struct cap_hdr *hdr;
8192
8193 if (curproxy == &defproxy) {
8194 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
8195 return -1;
8196 }
8197
8198 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
8199 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
8200 file, linenum, args[0], args[1]);
8201 return -1;
8202 }
8203 hdr = calloc(sizeof(struct cap_hdr), 1);
8204 hdr->next = curproxy->rsp_cap;
8205 hdr->name = strdup(args[3]);
8206 hdr->namelen = strlen(args[3]);
8207 hdr->len = atol(args[5]);
8208 hdr->index = curproxy->nb_rsp_cap++;
8209 curproxy->rsp_cap = hdr;
8210 curproxy->to_log |= LW_RSPHDR;
8211 }
8212 else {
8213 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008214 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008215 return -1;
8216 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008217 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008218 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008219 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008220 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008221 return 0;
8222 }
8223 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008224 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8225 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008226 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008227 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008228 curproxy->contimeout = atol(args[1]);
8229 }
8230 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008231 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008232 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
8233 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008234 return 0;
8235 }
8236 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008237 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8238 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008239 return -1;
8240 }
8241 curproxy->clitimeout = atol(args[1]);
8242 }
8243 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008244 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008245 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008246 return 0;
8247 }
8248 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008249 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8250 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01008251 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008252 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008253 curproxy->srvtimeout = atol(args[1]);
8254 }
8255 else if (!strcmp(args[0], "retries")) { /* connection retries */
8256 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008257 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
8258 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008259 return -1;
8260 }
8261 curproxy->conn_retries = atol(args[1]);
8262 }
willy tarreau9e138862006-05-14 23:06:28 +02008263 else if (!strcmp(args[0], "stats")) {
willy tarreau1f431b52006-05-21 14:46:15 +02008264 if (curproxy != &defproxy && curproxy->uri_auth == defproxy.uri_auth)
8265 curproxy->uri_auth = NULL; /* we must detach from the default config */
8266
willy tarreau9e138862006-05-14 23:06:28 +02008267 if (*(args[1]) == 0) {
willy tarreau1f431b52006-05-21 14:46:15 +02008268 Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'auth', 'scope' or 'enable'.\n", file, linenum, args[0]);
willy tarreau9e138862006-05-14 23:06:28 +02008269 return -1;
8270 } else if (!strcmp(args[1], "uri")) {
8271 if (*(args[2]) == 0) {
8272 Alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
8273 return -1;
8274 } else if (!stats_set_uri(&curproxy->uri_auth, args[2])) {
8275 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8276 return -1;
8277 }
8278 } else if (!strcmp(args[1], "realm")) {
8279 if (*(args[2]) == 0) {
8280 Alert("parsing [%s:%d] : 'realm' needs an realm name.\n", file, linenum);
8281 return -1;
8282 } else if (!stats_set_realm(&curproxy->uri_auth, args[2])) {
8283 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8284 return -1;
8285 }
8286 } else if (!strcmp(args[1], "auth")) {
8287 if (*(args[2]) == 0) {
8288 Alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
8289 return -1;
8290 } else if (!stats_add_auth(&curproxy->uri_auth, args[2])) {
8291 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8292 return -1;
8293 }
willy tarreau1f431b52006-05-21 14:46:15 +02008294 } else if (!strcmp(args[1], "scope")) {
8295 if (*(args[2]) == 0) {
8296 Alert("parsing [%s:%d] : 'scope' needs a proxy name.\n", file, linenum);
8297 return -1;
8298 } else if (!stats_add_scope(&curproxy->uri_auth, args[2])) {
8299 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8300 return -1;
8301 }
willy tarreau9e138862006-05-14 23:06:28 +02008302 } else if (!strcmp(args[1], "enable")) {
8303 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
8304 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8305 return -1;
8306 }
8307 } else {
8308 Alert("parsing [%s:%d] : unknown stats parameter '%s' (expects 'uri', 'realm', 'auth' or 'enable').\n",
8309 file, linenum, args[0]);
8310 return -1;
8311 }
8312 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008313 else if (!strcmp(args[0], "option")) {
8314 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008315 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008316 return -1;
8317 }
8318 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01008319 /* enable reconnections to dispatch */
8320 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01008321#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01008322 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01008323 /* enable transparent proxy connections */
8324 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01008325#endif
8326 else if (!strcmp(args[1], "keepalive"))
8327 /* enable keep-alive */
8328 curproxy->options |= PR_O_KEEPALIVE;
8329 else if (!strcmp(args[1], "forwardfor"))
8330 /* insert x-forwarded-for field */
8331 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01008332 else if (!strcmp(args[1], "logasap"))
8333 /* log as soon as possible, without waiting for the session to complete */
8334 curproxy->options |= PR_O_LOGASAP;
willy tarreau03a92de2006-05-21 18:26:53 +02008335 else if (!strcmp(args[1], "abortonclose"))
8336 /* abort connection if client closes during queue or connect() */
8337 curproxy->options |= PR_O_ABRT_CLOSE;
willy tarreau25c4ea52005-12-18 00:49:49 +01008338 else if (!strcmp(args[1], "httpclose"))
8339 /* force connection: close in both directions in HTTP mode */
8340 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01008341 else if (!strcmp(args[1], "forceclose"))
8342 /* force connection: close in both directions in HTTP mode and enforce end of session */
8343 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01008344 else if (!strcmp(args[1], "checkcache"))
8345 /* require examination of cacheability of the 'set-cookie' field */
8346 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01008347 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01008348 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01008349 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01008350 else if (!strcmp(args[1], "tcplog"))
8351 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01008352 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01008353 else if (!strcmp(args[1], "dontlognull")) {
8354 /* don't log empty requests */
8355 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008356 }
willy tarreaub952e1d2005-12-18 01:31:20 +01008357 else if (!strcmp(args[1], "tcpka")) {
8358 /* enable TCP keep-alives on client and server sessions */
8359 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
8360 }
8361 else if (!strcmp(args[1], "clitcpka")) {
8362 /* enable TCP keep-alives on client sessions */
8363 curproxy->options |= PR_O_TCP_CLI_KA;
8364 }
8365 else if (!strcmp(args[1], "srvtcpka")) {
8366 /* enable TCP keep-alives on server sessions */
8367 curproxy->options |= PR_O_TCP_SRV_KA;
8368 }
Willy TARREAU3481c462006-03-01 22:37:57 +01008369 else if (!strcmp(args[1], "allbackups")) {
8370 /* Use all backup servers simultaneously */
8371 curproxy->options |= PR_O_USE_ALL_BK;
8372 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008373 else if (!strcmp(args[1], "httpchk")) {
8374 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008375 if (curproxy->check_req != NULL) {
8376 free(curproxy->check_req);
8377 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008378 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01008379 if (!*args[2]) { /* no argument */
8380 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
8381 curproxy->check_len = strlen(DEF_CHECK_REQ);
8382 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01008383 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
8384 curproxy->check_req = (char *)malloc(reqlen);
8385 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
8386 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008387 } else { /* more arguments : METHOD URI [HTTP_VER] */
8388 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
8389 if (*args[4])
8390 reqlen += strlen(args[4]);
8391 else
8392 reqlen += strlen("HTTP/1.0");
8393
8394 curproxy->check_req = (char *)malloc(reqlen);
8395 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
8396 "%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 +01008397 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008398 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008399 else if (!strcmp(args[1], "persist")) {
8400 /* persist on using the server specified by the cookie, even when it's down */
8401 curproxy->options |= PR_O_PERSIST;
8402 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008403 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008404 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008405 return -1;
8406 }
8407 return 0;
8408 }
8409 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
8410 /* enable reconnections to dispatch */
8411 curproxy->options |= PR_O_REDISP;
8412 }
willy tarreaua1598082005-12-17 13:08:06 +01008413#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01008414 else if (!strcmp(args[0], "transparent")) {
8415 /* enable transparent proxy connections */
8416 curproxy->options |= PR_O_TRANSP;
8417 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008418#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01008419 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
8420 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008421 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008422 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008423 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008424 curproxy->maxconn = atol(args[1]);
8425 }
8426 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
8427 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008428 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008429 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008430 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008431 curproxy->grace = atol(args[1]);
8432 }
8433 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01008434 if (curproxy == &defproxy) {
8435 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8436 return -1;
8437 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008438 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008439 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008440 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008441 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008442 curproxy->dispatch_addr = *str2sa(args[1]);
8443 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008444 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01008445 if (*(args[1])) {
8446 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008447 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01008448 }
willy tarreau1a3442d2006-03-24 21:03:20 +01008449 else if (!strcmp(args[1], "source")) {
8450 curproxy->options |= PR_O_BALANCE_SH;
8451 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008452 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01008453 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008454 return -1;
8455 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008456 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008457 else /* if no option is set, use round-robin by default */
8458 curproxy->options |= PR_O_BALANCE_RR;
8459 }
8460 else if (!strcmp(args[0], "server")) { /* server address */
8461 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008462 char *rport;
8463 char *raddr;
8464 short realport;
8465 int do_check;
8466
8467 if (curproxy == &defproxy) {
8468 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8469 return -1;
8470 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008471
willy tarreaua41a8b42005-12-17 14:02:24 +01008472 if (!*args[2]) {
8473 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008474 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008475 return -1;
8476 }
8477 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
8478 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8479 return -1;
8480 }
willy tarreau0174f312005-12-18 01:02:42 +01008481
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008482 /* the servers are linked backwards first */
8483 newsrv->next = curproxy->srv;
8484 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01008485 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008486
willy tarreau18a957c2006-04-12 19:26:23 +02008487 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01008488 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01008489 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01008490 newsrv->id = strdup(args[1]);
8491
8492 /* several ways to check the port component :
8493 * - IP => port=+0, relative
8494 * - IP: => port=+0, relative
8495 * - IP:N => port=N, absolute
8496 * - IP:+N => port=+N, relative
8497 * - IP:-N => port=-N, relative
8498 */
8499 raddr = strdup(args[2]);
8500 rport = strchr(raddr, ':');
8501 if (rport) {
8502 *rport++ = 0;
8503 realport = atol(rport);
8504 if (!isdigit((int)*rport))
8505 newsrv->state |= SRV_MAPPORTS;
8506 } else {
8507 realport = 0;
8508 newsrv->state |= SRV_MAPPORTS;
8509 }
8510
8511 newsrv->addr = *str2sa(raddr);
8512 newsrv->addr.sin_port = htons(realport);
8513 free(raddr);
8514
willy tarreau9fe663a2005-12-17 13:02:59 +01008515 newsrv->curfd = -1; /* no health-check in progress */
8516 newsrv->inter = DEF_CHKINTR;
8517 newsrv->rise = DEF_RISETIME;
8518 newsrv->fall = DEF_FALLTIME;
8519 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
8520 cur_arg = 3;
8521 while (*args[cur_arg]) {
8522 if (!strcmp(args[cur_arg], "cookie")) {
8523 newsrv->cookie = strdup(args[cur_arg + 1]);
8524 newsrv->cklen = strlen(args[cur_arg + 1]);
8525 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01008526 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008527 else if (!strcmp(args[cur_arg], "rise")) {
8528 newsrv->rise = atol(args[cur_arg + 1]);
8529 newsrv->health = newsrv->rise;
8530 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01008531 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008532 else if (!strcmp(args[cur_arg], "fall")) {
8533 newsrv->fall = atol(args[cur_arg + 1]);
8534 cur_arg += 2;
8535 }
8536 else if (!strcmp(args[cur_arg], "inter")) {
8537 newsrv->inter = atol(args[cur_arg + 1]);
8538 cur_arg += 2;
8539 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008540 else if (!strcmp(args[cur_arg], "port")) {
8541 newsrv->check_port = atol(args[cur_arg + 1]);
8542 cur_arg += 2;
8543 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008544 else if (!strcmp(args[cur_arg], "backup")) {
8545 newsrv->state |= SRV_BACKUP;
8546 cur_arg ++;
8547 }
willy tarreaue3f023f2006-04-08 21:52:24 +02008548 else if (!strcmp(args[cur_arg], "weight")) {
8549 int w;
8550 w = atol(args[cur_arg + 1]);
8551 if (w < 1 || w > 256) {
8552 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
8553 file, linenum, newsrv->id, w);
8554 return -1;
8555 }
8556 newsrv->uweight = w - 1;
8557 cur_arg += 2;
8558 }
willy tarreau18a957c2006-04-12 19:26:23 +02008559 else if (!strcmp(args[cur_arg], "maxconn")) {
8560 newsrv->maxconn = atol(args[cur_arg + 1]);
8561 cur_arg += 2;
8562 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008563 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01008564 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01008565 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008566 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008567 }
willy tarreau0174f312005-12-18 01:02:42 +01008568 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
8569 if (!*args[cur_arg + 1]) {
8570 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
8571 file, linenum, "source");
8572 return -1;
8573 }
8574 newsrv->state |= SRV_BIND_SRC;
8575 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
8576 cur_arg += 2;
8577 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008578 else {
willy tarreaue3f023f2006-04-08 21:52:24 +02008579 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 +01008580 file, linenum, newsrv->id);
8581 return -1;
8582 }
8583 }
8584
8585 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008586 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
8587 newsrv->check_port = realport; /* by default */
8588 if (!newsrv->check_port) {
8589 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 +01008590 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01008591 return -1;
8592 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008593 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01008594 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008595
willy tarreau62084d42006-03-24 18:57:41 +01008596 if (newsrv->state & SRV_BACKUP)
8597 curproxy->srv_bck++;
8598 else
8599 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01008600 }
8601 else if (!strcmp(args[0], "log")) { /* syslog server address */
8602 struct sockaddr_in *sa;
8603 int facility;
8604
8605 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
8606 curproxy->logfac1 = global.logfac1;
8607 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01008608 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008609 curproxy->logfac2 = global.logfac2;
8610 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01008611 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01008612 }
8613 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01008614 int level;
8615
willy tarreau0f7af912005-12-17 12:21:26 +01008616 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
8617 if (!strcmp(log_facilities[facility], args[2]))
8618 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01008619
willy tarreau0f7af912005-12-17 12:21:26 +01008620 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008621 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01008622 exit(1);
8623 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008624
willy tarreau8337c6b2005-12-17 13:41:01 +01008625 level = 7; /* max syslog level = debug */
8626 if (*(args[3])) {
8627 while (level >= 0 && strcmp(log_levels[level], args[3]))
8628 level--;
8629 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008630 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008631 exit(1);
8632 }
8633 }
8634
willy tarreau0f7af912005-12-17 12:21:26 +01008635 sa = str2sa(args[1]);
8636 if (!sa->sin_port)
8637 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01008638
willy tarreau0f7af912005-12-17 12:21:26 +01008639 if (curproxy->logfac1 == -1) {
8640 curproxy->logsrv1 = *sa;
8641 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01008642 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01008643 }
8644 else if (curproxy->logfac2 == -1) {
8645 curproxy->logsrv2 = *sa;
8646 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01008647 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01008648 }
8649 else {
8650 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01008651 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008652 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008653 }
8654 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008655 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01008656 file, linenum);
8657 return -1;
8658 }
8659 }
willy tarreaua1598082005-12-17 13:08:06 +01008660 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01008661 if (!*args[1]) {
8662 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008663 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01008664 return -1;
8665 }
8666
8667 curproxy->source_addr = *str2sa(args[1]);
8668 curproxy->options |= PR_O_BIND_SRC;
8669 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008670 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
8671 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008672 if (curproxy == &defproxy) {
8673 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8674 return -1;
8675 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008676
8677 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008678 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8679 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008680 return -1;
8681 }
8682
8683 preg = calloc(1, sizeof(regex_t));
8684 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008685 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008686 return -1;
8687 }
8688
willy tarreauc1f47532005-12-18 01:08:26 +01008689 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8690 if (err) {
8691 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8692 file, linenum, *err);
8693 return -1;
8694 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008695 }
8696 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
8697 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008698 if (curproxy == &defproxy) {
8699 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8700 return -1;
8701 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008702
8703 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008704 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008705 return -1;
8706 }
8707
8708 preg = calloc(1, sizeof(regex_t));
8709 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008710 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008711 return -1;
8712 }
8713
8714 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8715 }
8716 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
8717 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008718 if (curproxy == &defproxy) {
8719 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8720 return -1;
8721 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008722
8723 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008724 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008725 return -1;
8726 }
8727
8728 preg = calloc(1, sizeof(regex_t));
8729 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008730 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008731 return -1;
8732 }
8733
8734 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8735 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008736 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
8737 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008738 if (curproxy == &defproxy) {
8739 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8740 return -1;
8741 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008742
8743 if (*(args[1]) == 0) {
8744 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8745 return -1;
8746 }
8747
8748 preg = calloc(1, sizeof(regex_t));
8749 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8750 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8751 return -1;
8752 }
8753
8754 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8755 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008756 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
8757 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008758 if (curproxy == &defproxy) {
8759 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8760 return -1;
8761 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008762
8763 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008764 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008765 return -1;
8766 }
8767
8768 preg = calloc(1, sizeof(regex_t));
8769 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008770 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008771 return -1;
8772 }
8773
8774 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8775 }
8776 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
8777 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008778 if (curproxy == &defproxy) {
8779 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8780 return -1;
8781 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008782
8783 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008784 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8785 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008786 return -1;
8787 }
8788
8789 preg = calloc(1, sizeof(regex_t));
8790 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008791 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008792 return -1;
8793 }
8794
willy tarreauc1f47532005-12-18 01:08:26 +01008795 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8796 if (err) {
8797 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8798 file, linenum, *err);
8799 return -1;
8800 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008801 }
8802 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
8803 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008804 if (curproxy == &defproxy) {
8805 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8806 return -1;
8807 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008808
8809 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008810 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008811 return -1;
8812 }
8813
8814 preg = calloc(1, sizeof(regex_t));
8815 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008816 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008817 return -1;
8818 }
8819
8820 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8821 }
8822 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
8823 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008824 if (curproxy == &defproxy) {
8825 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8826 return -1;
8827 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008828
8829 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008830 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008831 return -1;
8832 }
8833
8834 preg = calloc(1, sizeof(regex_t));
8835 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008836 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008837 return -1;
8838 }
8839
8840 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8841 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008842 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
8843 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008844 if (curproxy == &defproxy) {
8845 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8846 return -1;
8847 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008848
8849 if (*(args[1]) == 0) {
8850 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8851 return -1;
8852 }
8853
8854 preg = calloc(1, sizeof(regex_t));
8855 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8856 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8857 return -1;
8858 }
8859
8860 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8861 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008862 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
8863 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008864 if (curproxy == &defproxy) {
8865 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8866 return -1;
8867 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008868
8869 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008870 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008871 return -1;
8872 }
8873
8874 preg = calloc(1, sizeof(regex_t));
8875 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008876 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008877 return -1;
8878 }
8879
8880 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8881 }
8882 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008883 if (curproxy == &defproxy) {
8884 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8885 return -1;
8886 }
8887
willy tarreau9fe663a2005-12-17 13:02:59 +01008888 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008889 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008890 return 0;
8891 }
8892
8893 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008894 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008895 return -1;
8896 }
8897
willy tarreau4302f492005-12-18 01:00:37 +01008898 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
8899 }
8900 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
8901 regex_t *preg;
8902
8903 if (*(args[1]) == 0 || *(args[2]) == 0) {
8904 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8905 file, linenum, args[0]);
8906 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008907 }
willy tarreau4302f492005-12-18 01:00:37 +01008908
8909 preg = calloc(1, sizeof(regex_t));
8910 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8911 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8912 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008913 }
willy tarreau4302f492005-12-18 01:00:37 +01008914
willy tarreauc1f47532005-12-18 01:08:26 +01008915 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8916 if (err) {
8917 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8918 file, linenum, *err);
8919 return -1;
8920 }
willy tarreau4302f492005-12-18 01:00:37 +01008921 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008922 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
8923 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008924 if (curproxy == &defproxy) {
8925 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8926 return -1;
8927 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008928
8929 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008930 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008931 return -1;
8932 }
willy tarreaue39cd132005-12-17 13:00:18 +01008933
willy tarreau9fe663a2005-12-17 13:02:59 +01008934 preg = calloc(1, sizeof(regex_t));
8935 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008936 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008937 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008938 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008939
willy tarreauc1f47532005-12-18 01:08:26 +01008940 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8941 if (err) {
8942 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8943 file, linenum, *err);
8944 return -1;
8945 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008946 }
willy tarreau982249e2005-12-18 00:57:06 +01008947 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
8948 regex_t *preg;
8949 if (curproxy == &defproxy) {
8950 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8951 return -1;
8952 }
8953
8954 if (*(args[1]) == 0) {
8955 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8956 return -1;
8957 }
8958
8959 preg = calloc(1, sizeof(regex_t));
8960 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8961 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8962 return -1;
8963 }
8964
willy tarreauc1f47532005-12-18 01:08:26 +01008965 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8966 if (err) {
8967 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8968 file, linenum, *err);
8969 return -1;
8970 }
willy tarreau982249e2005-12-18 00:57:06 +01008971 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008972 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01008973 regex_t *preg;
8974 if (curproxy == &defproxy) {
8975 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8976 return -1;
8977 }
willy tarreaue39cd132005-12-17 13:00:18 +01008978
willy tarreaua41a8b42005-12-17 14:02:24 +01008979 if (*(args[1]) == 0 || *(args[2]) == 0) {
8980 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8981 file, linenum, args[0]);
8982 return -1;
8983 }
willy tarreaue39cd132005-12-17 13:00:18 +01008984
willy tarreaua41a8b42005-12-17 14:02:24 +01008985 preg = calloc(1, sizeof(regex_t));
8986 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8987 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8988 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008989 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008990
willy tarreauc1f47532005-12-18 01:08:26 +01008991 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8992 if (err) {
8993 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8994 file, linenum, *err);
8995 return -1;
8996 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008997 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008998 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
8999 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01009000 if (curproxy == &defproxy) {
9001 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9002 return -1;
9003 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009004
9005 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009006 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009007 return -1;
9008 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009009
willy tarreau9fe663a2005-12-17 13:02:59 +01009010 preg = calloc(1, sizeof(regex_t));
9011 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009012 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009013 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01009014 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009015
willy tarreauc1f47532005-12-18 01:08:26 +01009016 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
9017 if (err) {
9018 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
9019 file, linenum, *err);
9020 return -1;
9021 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009022 }
willy tarreau982249e2005-12-18 00:57:06 +01009023 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
9024 regex_t *preg;
9025 if (curproxy == &defproxy) {
9026 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9027 return -1;
9028 }
9029
9030 if (*(args[1]) == 0) {
9031 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
9032 return -1;
9033 }
9034
9035 preg = calloc(1, sizeof(regex_t));
9036 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
9037 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
9038 return -1;
9039 }
9040
willy tarreauc1f47532005-12-18 01:08:26 +01009041 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
9042 if (err) {
9043 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
9044 file, linenum, *err);
9045 return -1;
9046 }
willy tarreau982249e2005-12-18 00:57:06 +01009047 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009048 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01009049 if (curproxy == &defproxy) {
9050 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9051 return -1;
9052 }
9053
willy tarreau9fe663a2005-12-17 13:02:59 +01009054 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009055 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009056 return 0;
9057 }
9058
9059 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009060 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009061 return -1;
9062 }
9063
9064 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
9065 }
willy tarreauc1f47532005-12-18 01:08:26 +01009066 else if (!strcmp(args[0], "errorloc") ||
9067 !strcmp(args[0], "errorloc302") ||
9068 !strcmp(args[0], "errorloc303")) { /* error location */
9069 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009070 char *err;
9071
willy tarreaueedaa9f2005-12-17 14:08:03 +01009072 // if (curproxy == &defproxy) {
9073 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9074 // return -1;
9075 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01009076
willy tarreau8337c6b2005-12-17 13:41:01 +01009077 if (*(args[2]) == 0) {
9078 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
9079 return -1;
9080 }
9081
9082 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01009083 if (!strcmp(args[0], "errorloc303")) {
9084 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
9085 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
9086 } else {
9087 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
9088 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
9089 }
willy tarreau8337c6b2005-12-17 13:41:01 +01009090
9091 if (errnum == 400) {
9092 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009093 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009094 free(curproxy->errmsg.msg400);
9095 }
9096 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009097 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009098 }
9099 else if (errnum == 403) {
9100 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009101 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009102 free(curproxy->errmsg.msg403);
9103 }
9104 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009105 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009106 }
9107 else if (errnum == 408) {
9108 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009109 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009110 free(curproxy->errmsg.msg408);
9111 }
9112 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009113 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009114 }
9115 else if (errnum == 500) {
9116 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009117 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009118 free(curproxy->errmsg.msg500);
9119 }
9120 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009121 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009122 }
9123 else if (errnum == 502) {
9124 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009125 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009126 free(curproxy->errmsg.msg502);
9127 }
9128 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009129 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009130 }
9131 else if (errnum == 503) {
9132 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009133 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009134 free(curproxy->errmsg.msg503);
9135 }
9136 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009137 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009138 }
9139 else if (errnum == 504) {
9140 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009141 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009142 free(curproxy->errmsg.msg504);
9143 }
9144 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009145 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009146 }
9147 else {
9148 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
9149 free(err);
9150 }
9151 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009152 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01009153 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01009154 return -1;
9155 }
9156 return 0;
9157}
willy tarreaue39cd132005-12-17 13:00:18 +01009158
willy tarreau5cbea6f2005-12-17 12:48:26 +01009159
willy tarreau9fe663a2005-12-17 13:02:59 +01009160/*
9161 * This function reads and parses the configuration file given in the argument.
9162 * returns 0 if OK, -1 if error.
9163 */
9164int readcfgfile(char *file) {
9165 char thisline[256];
9166 char *line;
9167 FILE *f;
9168 int linenum = 0;
9169 char *end;
9170 char *args[MAX_LINE_ARGS];
9171 int arg;
9172 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01009173 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01009174 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01009175
willy tarreau9fe663a2005-12-17 13:02:59 +01009176 struct proxy *curproxy = NULL;
9177 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01009178
willy tarreau9fe663a2005-12-17 13:02:59 +01009179 if ((f=fopen(file,"r")) == NULL)
9180 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01009181
willy tarreaueedaa9f2005-12-17 14:08:03 +01009182 init_default_instance();
9183
willy tarreau9fe663a2005-12-17 13:02:59 +01009184 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
9185 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009186
willy tarreau9fe663a2005-12-17 13:02:59 +01009187 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01009188
willy tarreau9fe663a2005-12-17 13:02:59 +01009189 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01009190 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01009191 line++;
9192
9193 arg = 0;
9194 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01009195
willy tarreau9fe663a2005-12-17 13:02:59 +01009196 while (*line && arg < MAX_LINE_ARGS) {
9197 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
9198 * C equivalent value. Other combinations left unchanged (eg: \1).
9199 */
9200 if (*line == '\\') {
9201 int skip = 0;
9202 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
9203 *line = line[1];
9204 skip = 1;
9205 }
9206 else if (line[1] == 'r') {
9207 *line = '\r';
9208 skip = 1;
9209 }
9210 else if (line[1] == 'n') {
9211 *line = '\n';
9212 skip = 1;
9213 }
9214 else if (line[1] == 't') {
9215 *line = '\t';
9216 skip = 1;
9217 }
willy tarreauc1f47532005-12-18 01:08:26 +01009218 else if (line[1] == 'x') {
9219 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
9220 unsigned char hex1, hex2;
9221 hex1 = toupper(line[2]) - '0';
9222 hex2 = toupper(line[3]) - '0';
9223 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
9224 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
9225 *line = (hex1<<4) + hex2;
9226 skip = 3;
9227 }
9228 else {
9229 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
9230 return -1;
9231 }
9232 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009233 if (skip) {
9234 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
9235 end -= skip;
9236 }
9237 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01009238 }
willy tarreaua1598082005-12-17 13:08:06 +01009239 else if (*line == '#' || *line == '\n' || *line == '\r') {
9240 /* end of string, end of loop */
9241 *line = 0;
9242 break;
9243 }
willy tarreauc29948c2005-12-17 13:10:27 +01009244 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009245 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01009246 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01009247 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01009248 line++;
9249 args[++arg] = line;
9250 }
9251 else {
9252 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01009253 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009254 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009255
willy tarreau9fe663a2005-12-17 13:02:59 +01009256 /* empty line */
9257 if (!**args)
9258 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01009259
willy tarreau9fe663a2005-12-17 13:02:59 +01009260 /* zero out remaining args */
9261 while (++arg < MAX_LINE_ARGS) {
9262 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009263 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009264
willy tarreaua41a8b42005-12-17 14:02:24 +01009265 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01009266 confsect = CFG_LISTEN;
9267 else if (!strcmp(args[0], "global")) /* global config */
9268 confsect = CFG_GLOBAL;
9269 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01009270
willy tarreau9fe663a2005-12-17 13:02:59 +01009271 switch (confsect) {
9272 case CFG_LISTEN:
9273 if (cfg_parse_listen(file, linenum, args) < 0)
9274 return -1;
9275 break;
9276 case CFG_GLOBAL:
9277 if (cfg_parse_global(file, linenum, args) < 0)
9278 return -1;
9279 break;
9280 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01009281 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009282 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01009283 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009284
9285
willy tarreau0f7af912005-12-17 12:21:26 +01009286 }
9287 fclose(f);
9288
9289 /*
9290 * Now, check for the integrity of all that we have collected.
9291 */
9292
Willy TARREAU3759f982006-03-01 22:44:17 +01009293 /* will be needed further to delay some tasks */
9294 tv_now(&now);
9295
willy tarreau0f7af912005-12-17 12:21:26 +01009296 if ((curproxy = proxy) == NULL) {
9297 Alert("parsing %s : no <listen> line. Nothing to do !\n",
9298 file);
9299 return -1;
9300 }
9301
9302 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01009303 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01009304 curproxy = curproxy->next;
9305 continue;
9306 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009307
9308 if (curproxy->listen == NULL) {
9309 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);
9310 cfgerr++;
9311 }
9312 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01009313 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01009314 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01009315 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
9316 file, curproxy->id);
9317 cfgerr++;
9318 }
9319 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
9320 if (curproxy->options & PR_O_TRANSP) {
9321 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
9322 file, curproxy->id);
9323 cfgerr++;
9324 }
willy tarreau38d79062006-05-21 14:47:13 +02009325#ifdef WE_DONT_SUPPORT_SERVERLESS_LISTENERS
willy tarreau5cbea6f2005-12-17 12:48:26 +01009326 else if (curproxy->srv == NULL) {
9327 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
9328 file, curproxy->id);
9329 cfgerr++;
9330 }
willy tarreau38d79062006-05-21 14:47:13 +02009331#endif
willy tarreaua1598082005-12-17 13:08:06 +01009332 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01009333 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
9334 file, curproxy->id);
9335 }
9336 }
9337 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01009338 if (curproxy->cookie_name != NULL) {
9339 Warning("parsing %s : cookie will be ignored for listener %s.\n",
9340 file, curproxy->id);
9341 }
9342 if ((newsrv = curproxy->srv) != NULL) {
9343 Warning("parsing %s : servers will be ignored for listener %s.\n",
9344 file, curproxy->id);
9345 }
willy tarreaue39cd132005-12-17 13:00:18 +01009346 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01009347 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
9348 file, curproxy->id);
9349 }
willy tarreaue39cd132005-12-17 13:00:18 +01009350 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01009351 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
9352 file, curproxy->id);
9353 }
9354 }
9355 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
9356 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
9357 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
9358 file, curproxy->id);
9359 cfgerr++;
9360 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009361 }
willy tarreaue3f023f2006-04-08 21:52:24 +02009362
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009363 /* first, we will invert the servers list order */
9364 newsrv = NULL;
9365 while (curproxy->srv) {
9366 struct server *next;
9367
9368 next = curproxy->srv->next;
9369 curproxy->srv->next = newsrv;
9370 newsrv = curproxy->srv;
9371 if (!next)
9372 break;
9373 curproxy->srv = next;
9374 }
9375
9376 /* now, newsrv == curproxy->srv */
9377 if (newsrv) {
9378 struct server *srv;
9379 int pgcd;
9380 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02009381
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009382 /* We will factor the weights to reduce the table,
9383 * using Euclide's largest common divisor algorithm
9384 */
9385 pgcd = newsrv->uweight + 1;
9386 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
9387 int t, w;
9388
9389 w = srv->uweight + 1;
9390 while (w) {
9391 t = pgcd % w;
9392 pgcd = w;
9393 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02009394 }
willy tarreau0f7af912005-12-17 12:21:26 +01009395 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009396
9397 act = bck = 0;
9398 for (srv = newsrv; srv; srv = srv->next) {
9399 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
9400 if (srv->state & SRV_BACKUP)
9401 bck += srv->eweight + 1;
9402 else
9403 act += srv->eweight + 1;
9404 }
9405
9406 /* this is the largest map we will ever need for this servers list */
9407 if (act < bck)
9408 act = bck;
9409
9410 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
9411 /* recounts servers and their weights */
9412 recount_servers(curproxy);
9413 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01009414 }
willy tarreau25c4ea52005-12-18 00:49:49 +01009415
9416 if (curproxy->options & PR_O_LOGASAP)
9417 curproxy->to_log &= ~LW_BYTES;
9418
willy tarreau8337c6b2005-12-17 13:41:01 +01009419 if (curproxy->errmsg.msg400 == NULL) {
9420 curproxy->errmsg.msg400 = (char *)HTTP_400;
9421 curproxy->errmsg.len400 = strlen(HTTP_400);
9422 }
9423 if (curproxy->errmsg.msg403 == NULL) {
9424 curproxy->errmsg.msg403 = (char *)HTTP_403;
9425 curproxy->errmsg.len403 = strlen(HTTP_403);
9426 }
9427 if (curproxy->errmsg.msg408 == NULL) {
9428 curproxy->errmsg.msg408 = (char *)HTTP_408;
9429 curproxy->errmsg.len408 = strlen(HTTP_408);
9430 }
9431 if (curproxy->errmsg.msg500 == NULL) {
9432 curproxy->errmsg.msg500 = (char *)HTTP_500;
9433 curproxy->errmsg.len500 = strlen(HTTP_500);
9434 }
9435 if (curproxy->errmsg.msg502 == NULL) {
9436 curproxy->errmsg.msg502 = (char *)HTTP_502;
9437 curproxy->errmsg.len502 = strlen(HTTP_502);
9438 }
9439 if (curproxy->errmsg.msg503 == NULL) {
9440 curproxy->errmsg.msg503 = (char *)HTTP_503;
9441 curproxy->errmsg.len503 = strlen(HTTP_503);
9442 }
9443 if (curproxy->errmsg.msg504 == NULL) {
9444 curproxy->errmsg.msg504 = (char *)HTTP_504;
9445 curproxy->errmsg.len504 = strlen(HTTP_504);
9446 }
Willy TARREAU3759f982006-03-01 22:44:17 +01009447
willy tarreau59a6cc22006-05-12 01:29:08 +02009448 /*
9449 * If this server supports a maxconn parameter, it needs a dedicated
9450 * tasks to fill the emptied slots when a connection leaves.
9451 */
9452 newsrv = curproxy->srv;
9453 while (newsrv != NULL) {
9454 if (newsrv->maxconn > 0) {
9455 struct task *t;
9456
9457 if ((t = pool_alloc(task)) == NULL) {
9458 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
9459 return -1;
9460 }
9461
9462 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
9463 t->wq = LIST_HEAD(wait_queue[1]); /* already assigned to the eternity queue */
9464 t->state = TASK_IDLE;
9465 t->process = process_srv_queue;
9466 t->context = newsrv;
9467 newsrv->queue_mgt = t;
9468
9469 /* never run it unless specifically woken up */
9470 tv_eternity(&t->expire);
9471 task_queue(t);
9472 }
9473 newsrv = newsrv->next;
9474 }
9475
Willy TARREAU3759f982006-03-01 22:44:17 +01009476 /* now we'll start this proxy's health checks if any */
9477 /* 1- count the checkers to run simultaneously */
9478 nbchk = 0;
9479 mininter = 0;
9480 newsrv = curproxy->srv;
9481 while (newsrv != NULL) {
9482 if (newsrv->state & SRV_CHECKED) {
9483 if (!mininter || mininter > newsrv->inter)
9484 mininter = newsrv->inter;
9485 nbchk++;
9486 }
9487 newsrv = newsrv->next;
9488 }
9489
9490 /* 2- start them as far as possible from each others while respecting
9491 * their own intervals. For this, we will start them after their own
9492 * interval added to the min interval divided by the number of servers,
9493 * weighted by the server's position in the list.
9494 */
9495 if (nbchk > 0) {
9496 struct task *t;
9497 int srvpos;
9498
9499 newsrv = curproxy->srv;
9500 srvpos = 0;
9501 while (newsrv != NULL) {
9502 /* should this server be checked ? */
9503 if (newsrv->state & SRV_CHECKED) {
9504 if ((t = pool_alloc(task)) == NULL) {
9505 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
9506 return -1;
9507 }
9508
9509 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02009510 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
Willy TARREAU3759f982006-03-01 22:44:17 +01009511 t->state = TASK_IDLE;
9512 t->process = process_chk;
9513 t->context = newsrv;
9514
9515 /* check this every ms */
9516 tv_delayfrom(&t->expire, &now,
9517 newsrv->inter + mininter * srvpos / nbchk);
9518 task_queue(t);
9519 //task_wakeup(&rq, t);
9520 srvpos++;
9521 }
9522 newsrv = newsrv->next;
9523 }
9524 }
9525
willy tarreau0f7af912005-12-17 12:21:26 +01009526 curproxy = curproxy->next;
9527 }
9528 if (cfgerr > 0) {
9529 Alert("Errors found in configuration file, aborting.\n");
9530 return -1;
9531 }
9532 else
9533 return 0;
9534}
9535
9536
9537/*
9538 * This function initializes all the necessary variables. It only returns
9539 * if everything is OK. If something fails, it exits.
9540 */
9541void init(int argc, char **argv) {
9542 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01009543 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01009544 char *old_argv = *argv;
9545 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009546 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009547
9548 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01009549 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01009550 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01009551 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01009552 exit(1);
9553 }
9554
willy tarreau746e26b2006-03-25 11:14:35 +01009555#ifdef HAPROXY_MEMMAX
9556 global.rlimit_memmax = HAPROXY_MEMMAX;
9557#endif
9558
Willy TARREAUa9e75f62006-03-01 22:27:48 +01009559 /* initialize the libc's localtime structures once for all so that we
9560 * won't be missing memory if we want to send alerts under OOM conditions.
9561 */
9562 tv_now(&now);
9563 localtime(&now.tv_sec);
willy tarreaue0331262006-05-15 03:02:46 +02009564 start_date = now;
Willy TARREAUa9e75f62006-03-01 22:27:48 +01009565
willy tarreau4302f492005-12-18 01:00:37 +01009566 /* initialize the log header encoding map : '{|}"#' should be encoded with
9567 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
9568 * URL encoding only requires '"', '#' to be encoded as well as non-
9569 * printable characters above.
9570 */
9571 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
9572 memset(url_encode_map, 0, sizeof(url_encode_map));
9573 for (i = 0; i < 32; i++) {
9574 FD_SET(i, hdr_encode_map);
9575 FD_SET(i, url_encode_map);
9576 }
9577 for (i = 127; i < 256; i++) {
9578 FD_SET(i, hdr_encode_map);
9579 FD_SET(i, url_encode_map);
9580 }
9581
9582 tmp = "\"#{|}";
9583 while (*tmp) {
9584 FD_SET(*tmp, hdr_encode_map);
9585 tmp++;
9586 }
9587
9588 tmp = "\"#";
9589 while (*tmp) {
9590 FD_SET(*tmp, url_encode_map);
9591 tmp++;
9592 }
9593
willy tarreau64a3cc32005-12-18 01:13:11 +01009594 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
9595#if defined(ENABLE_POLL)
9596 cfg_polling_mechanism |= POLL_USE_POLL;
9597#endif
9598#if defined(ENABLE_EPOLL)
9599 cfg_polling_mechanism |= POLL_USE_EPOLL;
9600#endif
9601
willy tarreau0f7af912005-12-17 12:21:26 +01009602 pid = getpid();
9603 progname = *argv;
9604 while ((tmp = strchr(progname, '/')) != NULL)
9605 progname = tmp + 1;
9606
9607 argc--; argv++;
9608 while (argc > 0) {
9609 char *flag;
9610
9611 if (**argv == '-') {
9612 flag = *argv+1;
9613
9614 /* 1 arg */
9615 if (*flag == 'v') {
9616 display_version();
9617 exit(0);
9618 }
willy tarreau1c2ad212005-12-18 01:11:29 +01009619#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009620 else if (*flag == 'd' && flag[1] == 'e')
9621 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009622#endif
9623#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009624 else if (*flag == 'd' && flag[1] == 'p')
9625 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009626#endif
willy tarreau982249e2005-12-18 00:57:06 +01009627 else if (*flag == 'V')
9628 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009629 else if (*flag == 'd' && flag[1] == 'b')
9630 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01009631 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01009632 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01009633 else if (*flag == 'c')
9634 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01009635 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01009636 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009637 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01009638 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01009639 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
9640 /* list of pids to finish ('f') or terminate ('t') */
9641
9642 if (flag[1] == 'f')
9643 oldpids_sig = SIGUSR1; /* finish then exit */
9644 else
9645 oldpids_sig = SIGTERM; /* terminate immediately */
9646 argv++; argc--;
9647
9648 if (argc > 0) {
9649 oldpids = calloc(argc, sizeof(int));
9650 while (argc > 0) {
9651 oldpids[nb_oldpids] = atol(*argv);
9652 if (oldpids[nb_oldpids] <= 0)
9653 usage(old_argv);
9654 argc--; argv++;
9655 nb_oldpids++;
9656 }
9657 }
9658 }
willy tarreau2c513732006-04-15 19:25:16 +02009659#if STATTIME > 0
9660 else if (*flag == 's')
9661 arg_mode |= MODE_STATS;
9662 else if (*flag == 'l')
9663 arg_mode |= MODE_LOG;
9664#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009665 else { /* >=2 args */
9666 argv++; argc--;
9667 if (argc == 0)
9668 usage(old_argv);
9669
9670 switch (*flag) {
9671 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01009672 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01009673 case 'N' : cfg_maxpconn = atol(*argv); break;
9674 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009675 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01009676 default: usage(old_argv);
9677 }
9678 }
9679 }
9680 else
9681 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01009682 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01009683 }
9684
willy tarreaud0fb4652005-12-18 01:32:04 +01009685 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009686 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
9687 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01009688
willy tarreau0f7af912005-12-17 12:21:26 +01009689 if (!cfg_cfgfile)
9690 usage(old_argv);
9691
9692 gethostname(hostname, MAX_HOSTNAME_LEN);
9693
willy tarreau12350152005-12-18 01:03:27 +01009694 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01009695 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01009696 if (readcfgfile(cfg_cfgfile) < 0) {
9697 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
9698 exit(1);
9699 }
willy tarreau12350152005-12-18 01:03:27 +01009700 if (have_appsession)
9701 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01009702
willy tarreau982249e2005-12-18 00:57:06 +01009703 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01009704 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
9705 exit(0);
9706 }
9707
willy tarreau9fe663a2005-12-17 13:02:59 +01009708 if (cfg_maxconn > 0)
9709 global.maxconn = cfg_maxconn;
9710
willy tarreaufe2c5c12005-12-17 14:14:34 +01009711 if (cfg_pidfile) {
9712 if (global.pidfile)
9713 free(global.pidfile);
9714 global.pidfile = strdup(cfg_pidfile);
9715 }
9716
willy tarreau9fe663a2005-12-17 13:02:59 +01009717 if (global.maxconn == 0)
9718 global.maxconn = DEFAULT_MAXCONN;
9719
Willy TARREAU203b0b62006-03-12 18:00:28 +01009720 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01009721
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009722 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009723 /* command line debug mode inhibits configuration mode */
9724 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
9725 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009726 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
9727 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01009728
9729 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
9730 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
9731 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
9732 }
9733
9734 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009735 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
9736 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01009737 global.nbproc = 1;
9738 }
9739
9740 if (global.nbproc < 1)
9741 global.nbproc = 1;
9742
willy tarreau0f7af912005-12-17 12:21:26 +01009743 StaticReadEvent = (fd_set *)calloc(1,
9744 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01009745 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01009746 StaticWriteEvent = (fd_set *)calloc(1,
9747 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01009748 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01009749
9750 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01009751 sizeof(struct fdtab) * (global.maxsock));
9752 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01009753 fdtab[i].state = FD_STCLOSE;
9754 }
9755}
9756
9757/*
willy tarreau41310e72006-03-25 18:17:56 +01009758 * this function starts all the proxies. Its return value is composed from
9759 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
9760 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01009761 */
willy tarreau41310e72006-03-25 18:17:56 +01009762int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01009763 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01009764 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01009765 int err = ERR_NONE;
9766 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01009767
9768 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01009769 if (curproxy->state != PR_STNEW)
9770 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01009771
willy tarreau41310e72006-03-25 18:17:56 +01009772 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01009773 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01009774 if (listener->fd != -1)
9775 continue; /* already initialized */
9776
9777 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
9778 if (verbose)
9779 Alert("cannot create listening socket for proxy %s. Aborting.\n",
9780 curproxy->id);
9781 err |= ERR_RETRYABLE;
9782 pxerr |= 1;
9783 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009784 }
willy tarreau0f7af912005-12-17 12:21:26 +01009785
willy tarreaua41a8b42005-12-17 14:02:24 +01009786 if (fd >= global.maxsock) {
9787 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
9788 curproxy->id);
9789 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009790 err |= ERR_FATAL;
9791 pxerr |= 1;
9792 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009793 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009794
willy tarreaua41a8b42005-12-17 14:02:24 +01009795 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
9796 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
9797 (char *) &one, sizeof(one)) == -1)) {
9798 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
9799 curproxy->id);
9800 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009801 err |= ERR_FATAL;
9802 pxerr |= 1;
9803 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009804 }
willy tarreau0f7af912005-12-17 12:21:26 +01009805
willy tarreaua41a8b42005-12-17 14:02:24 +01009806 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
9807 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
9808 curproxy->id);
9809 }
willy tarreau0f7af912005-12-17 12:21:26 +01009810
willy tarreaufac1a862006-05-21 10:20:28 +02009811#ifdef SO_REUSEPORT
9812 /* OpenBSD supports this. As it's present in old libc versions of Linux,
9813 * it might return an error that we will silently ignore.
9814 */
9815 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one));
9816#endif
willy tarreaua41a8b42005-12-17 14:02:24 +01009817 if (bind(fd,
9818 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01009819 listener->addr.ss_family == AF_INET6 ?
9820 sizeof(struct sockaddr_in6) :
9821 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009822 if (verbose)
9823 Alert("cannot bind socket for proxy %s. Aborting.\n",
9824 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009825 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009826 err |= ERR_RETRYABLE;
9827 pxerr |= 1;
9828 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009829 }
willy tarreau0f7af912005-12-17 12:21:26 +01009830
willy tarreaua41a8b42005-12-17 14:02:24 +01009831 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009832 if (verbose)
9833 Alert("cannot listen to socket for proxy %s. Aborting.\n",
9834 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009835 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009836 err |= ERR_RETRYABLE;
9837 pxerr |= 1;
9838 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009839 }
willy tarreau0f7af912005-12-17 12:21:26 +01009840
willy tarreau41310e72006-03-25 18:17:56 +01009841 /* the socket is ready */
9842 listener->fd = fd;
9843
willy tarreaua41a8b42005-12-17 14:02:24 +01009844 /* the function for the accept() event */
9845 fdtab[fd].read = &event_accept;
9846 fdtab[fd].write = NULL; /* never called */
9847 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01009848 fdtab[fd].state = FD_STLISTEN;
9849 FD_SET(fd, StaticReadEvent);
9850 fd_insert(fd);
9851 listeners++;
9852 }
willy tarreau41310e72006-03-25 18:17:56 +01009853
9854 if (!pxerr) {
9855 curproxy->state = PR_STRUN;
9856 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
9857 }
willy tarreau0f7af912005-12-17 12:21:26 +01009858 }
willy tarreau41310e72006-03-25 18:17:56 +01009859
9860 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01009861}
9862
willy tarreaub952e1d2005-12-18 01:31:20 +01009863int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01009864
9865 appsess *temp1,*temp2;
9866 temp1 = (appsess *)key1;
9867 temp2 = (appsess *)key2;
9868
9869 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
9870 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
9871
9872 return (strcmp(temp1->sessid,temp2->sessid) == 0);
9873}/* end match_str */
9874
willy tarreaub952e1d2005-12-18 01:31:20 +01009875void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01009876 appsess *temp1;
9877
9878 //printf("destroy called\n");
9879 temp1 = (appsess *)data;
9880
9881 if (temp1->sessid)
9882 pool_free_to(apools.sessid, temp1->sessid);
9883
9884 if (temp1->serverid)
9885 pool_free_to(apools.serverid, temp1->serverid);
9886
9887 pool_free(appsess, temp1);
9888} /* end destroy */
9889
9890void appsession_cleanup( void )
9891{
9892 struct proxy *p = proxy;
9893
9894 while(p) {
9895 chtbl_destroy(&(p->htbl_proxy));
9896 p = p->next;
9897 }
9898}/* end appsession_cleanup() */
9899
9900void pool_destroy(void **pool)
9901{
9902 void *temp, *next;
9903 next = pool;
9904 while (next) {
9905 temp = next;
9906 next = *(void **)temp;
9907 free(temp);
9908 }
9909}/* end pool_destroy() */
9910
willy tarreaub952e1d2005-12-18 01:31:20 +01009911void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01009912 struct proxy *p = proxy;
9913 struct cap_hdr *h,*h_next;
9914 struct server *s,*s_next;
9915 struct listener *l,*l_next;
9916
9917 while (p) {
9918 if (p->id)
9919 free(p->id);
9920
9921 if (p->check_req)
9922 free(p->check_req);
9923
9924 if (p->cookie_name)
9925 free(p->cookie_name);
9926
9927 if (p->capture_name)
9928 free(p->capture_name);
9929
9930 /* only strup if the user have set in config.
9931 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01009932 if (p->errmsg.msg400) free(p->errmsg.msg400);
9933 if (p->errmsg.msg403) free(p->errmsg.msg403);
9934 if (p->errmsg.msg408) free(p->errmsg.msg408);
9935 if (p->errmsg.msg500) free(p->errmsg.msg500);
9936 if (p->errmsg.msg502) free(p->errmsg.msg502);
9937 if (p->errmsg.msg503) free(p->errmsg.msg503);
9938 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01009939 */
9940 if (p->appsession_name)
9941 free(p->appsession_name);
9942
9943 h = p->req_cap;
9944 while (h) {
9945 h_next = h->next;
9946 if (h->name)
9947 free(h->name);
9948 pool_destroy(h->pool);
9949 free(h);
9950 h = h_next;
9951 }/* end while(h) */
9952
9953 h = p->rsp_cap;
9954 while (h) {
9955 h_next = h->next;
9956 if (h->name)
9957 free(h->name);
9958
9959 pool_destroy(h->pool);
9960 free(h);
9961 h = h_next;
9962 }/* end while(h) */
9963
9964 s = p->srv;
9965 while (s) {
9966 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01009967 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01009968 free(s->id);
9969
willy tarreaub952e1d2005-12-18 01:31:20 +01009970 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01009971 free(s->cookie);
9972
9973 free(s);
9974 s = s_next;
9975 }/* end while(s) */
9976
9977 l = p->listen;
9978 while (l) {
9979 l_next = l->next;
9980 free(l);
9981 l = l_next;
9982 }/* end while(l) */
9983
9984 pool_destroy((void **) p->req_cap_pool);
9985 pool_destroy((void **) p->rsp_cap_pool);
9986 p = p->next;
9987 }/* end while(p) */
9988
9989 if (global.chroot) free(global.chroot);
9990 if (global.pidfile) free(global.pidfile);
9991
willy tarreau12350152005-12-18 01:03:27 +01009992 if (StaticReadEvent) free(StaticReadEvent);
9993 if (StaticWriteEvent) free(StaticWriteEvent);
9994 if (fdtab) free(fdtab);
9995
9996 pool_destroy(pool_session);
9997 pool_destroy(pool_buffer);
9998 pool_destroy(pool_fdtab);
9999 pool_destroy(pool_requri);
10000 pool_destroy(pool_task);
10001 pool_destroy(pool_capture);
10002 pool_destroy(pool_appsess);
10003
10004 if (have_appsession) {
10005 pool_destroy(apools.serverid);
10006 pool_destroy(apools.sessid);
10007 }
10008} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +010010009
willy tarreau41310e72006-03-25 18:17:56 +010010010/* sends the signal <sig> to all pids found in <oldpids> */
10011static void tell_old_pids(int sig) {
10012 int p;
10013 for (p = 0; p < nb_oldpids; p++)
10014 kill(oldpids[p], sig);
10015}
10016
willy tarreau0f7af912005-12-17 12:21:26 +010010017int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +010010018 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +010010019 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +010010020 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +010010021 init(argc, argv);
10022
willy tarreau0f7af912005-12-17 12:21:26 +010010023 signal(SIGQUIT, dump);
10024 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +010010025 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +010010026#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +010010027 signal(SIGINT, sig_int);
10028 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +010010029#endif
willy tarreau0f7af912005-12-17 12:21:26 +010010030
10031 /* on very high loads, a sigpipe sometimes happen just between the
10032 * getsockopt() which tells "it's OK to write", and the following write :-(
10033 */
willy tarreau3242e862005-12-17 12:27:53 +010010034#ifndef MSG_NOSIGNAL
10035 signal(SIGPIPE, SIG_IGN);
10036#endif
willy tarreau0f7af912005-12-17 12:21:26 +010010037
willy tarreau41310e72006-03-25 18:17:56 +010010038 /* We will loop at most 100 times with 10 ms delay each time.
10039 * That's at most 1 second. We only send a signal to old pids
10040 * if we cannot grab at least one port.
10041 */
10042 retry = MAX_START_RETRIES;
10043 err = ERR_NONE;
10044 while (retry >= 0) {
10045 struct timeval w;
10046 err = start_proxies(retry == 0 || nb_oldpids == 0);
10047 if (err != ERR_RETRYABLE)
10048 break;
10049 if (nb_oldpids == 0)
10050 break;
10051
Willy TARREAU007aa462006-05-14 09:55:23 +020010052 /* FIXME-20060514: Solaris and OpenBSD do not support shutdown() on
10053 * listening sockets. So on those platforms, it would be wiser to
10054 * simply send SIGUSR1, which will not be undoable.
10055 */
willy tarreau41310e72006-03-25 18:17:56 +010010056 tell_old_pids(SIGTTOU);
10057 /* give some time to old processes to stop listening */
10058 w.tv_sec = 0;
10059 w.tv_usec = 10*1000;
10060 select(0, NULL, NULL, NULL, &w);
10061 retry--;
10062 }
10063
10064 /* Note: start_proxies() sends an alert when it fails. */
10065 if (err != ERR_NONE) {
10066 if (retry != MAX_START_RETRIES && nb_oldpids)
10067 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +010010068 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +010010069 }
willy tarreaud0fb4652005-12-18 01:32:04 +010010070
10071 if (listeners == 0) {
10072 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +010010073 /* Note: we don't have to send anything to the old pids because we
10074 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +010010075 exit(1);
10076 }
10077
willy tarreaudbd3bef2006-01-20 19:35:18 +010010078 /* prepare pause/play signals */
10079 signal(SIGTTOU, sig_pause);
10080 signal(SIGTTIN, sig_listen);
10081
Willy TARREAUe3283d12006-03-01 22:15:29 +010010082 if (global.mode & MODE_DAEMON) {
10083 global.mode &= ~MODE_VERBOSE;
10084 global.mode |= MODE_QUIET;
10085 }
10086
willy tarreaud0fb4652005-12-18 01:32:04 +010010087 /* MODE_QUIET can inhibit alerts and warnings below this line */
10088
10089 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +010010090 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +010010091 /* detach from the tty */
10092 fclose(stdin); fclose(stdout); fclose(stderr);
10093 close(0); close(1); close(2);
10094 }
willy tarreau0f7af912005-12-17 12:21:26 +010010095
willy tarreaufe2c5c12005-12-17 14:14:34 +010010096 /* open log & pid files before the chroot */
10097 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
10098 int pidfd;
10099 unlink(global.pidfile);
10100 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
10101 if (pidfd < 0) {
10102 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +010010103 if (nb_oldpids)
10104 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +010010105 exit(1);
10106 }
10107 pidfile = fdopen(pidfd, "w");
10108 }
willy tarreau9fe663a2005-12-17 13:02:59 +010010109
10110 /* chroot if needed */
10111 if (global.chroot != NULL) {
10112 if (chroot(global.chroot) == -1) {
10113 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +010010114 if (nb_oldpids)
10115 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +010010116 }
10117 chdir("/");
10118 }
10119
willy tarreaub1285d52005-12-18 01:20:14 +010010120 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +010010121 if (!global.rlimit_nofile)
10122 global.rlimit_nofile = global.maxsock;
10123
willy tarreaub1285d52005-12-18 01:20:14 +010010124 if (global.rlimit_nofile) {
10125 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
10126 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
10127 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
10128 }
willy tarreau746e26b2006-03-25 11:14:35 +010010129 }
10130
10131 if (global.rlimit_memmax) {
10132 limit.rlim_cur = limit.rlim_max =
10133 global.rlimit_memmax * 1048576 / global.nbproc;
10134#ifdef RLIMIT_AS
10135 if (setrlimit(RLIMIT_AS, &limit) == -1) {
10136 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
10137 argv[0], global.rlimit_memmax);
10138 }
10139#else
10140 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
10141 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
10142 argv[0], global.rlimit_memmax);
10143 }
10144#endif
willy tarreaub1285d52005-12-18 01:20:14 +010010145 }
10146
willy tarreau41310e72006-03-25 18:17:56 +010010147 if (nb_oldpids)
10148 tell_old_pids(oldpids_sig);
10149
10150 /* Note that any error at this stage will be fatal because we will not
10151 * be able to restart the old pids.
10152 */
10153
willy tarreau9fe663a2005-12-17 13:02:59 +010010154 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +010010155 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +010010156 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
10157 exit(1);
10158 }
10159
willy tarreau036e1ce2005-12-17 13:46:33 +010010160 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +010010161 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
10162 exit(1);
10163 }
10164
willy tarreaub1285d52005-12-18 01:20:14 +010010165 /* check ulimits */
10166 limit.rlim_cur = limit.rlim_max = 0;
10167 getrlimit(RLIMIT_NOFILE, &limit);
10168 if (limit.rlim_cur < global.maxsock) {
10169 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",
10170 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
10171 }
10172
willy tarreau9fe663a2005-12-17 13:02:59 +010010173 if (global.mode & MODE_DAEMON) {
10174 int ret = 0;
10175 int proc;
10176
10177 /* the father launches the required number of processes */
10178 for (proc = 0; proc < global.nbproc; proc++) {
10179 ret = fork();
10180 if (ret < 0) {
10181 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +010010182 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +010010183 exit(1); /* there has been an error */
10184 }
10185 else if (ret == 0) /* child breaks here */
10186 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +010010187 if (pidfile != NULL) {
10188 fprintf(pidfile, "%d\n", ret);
10189 fflush(pidfile);
10190 }
willy tarreau9fe663a2005-12-17 13:02:59 +010010191 }
willy tarreaufe2c5c12005-12-17 14:14:34 +010010192 /* close the pidfile both in children and father */
10193 if (pidfile != NULL)
10194 fclose(pidfile);
10195 free(global.pidfile);
10196
willy tarreau9fe663a2005-12-17 13:02:59 +010010197 if (proc == global.nbproc)
10198 exit(0); /* parent must leave */
10199
willy tarreau750a4722005-12-17 13:21:24 +010010200 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
10201 * that we can detach from the TTY. We MUST NOT do it in other cases since
10202 * it would have already be done, and 0-2 would have been affected to listening
10203 * sockets
10204 */
10205 if (!(global.mode & MODE_QUIET)) {
10206 /* detach from the tty */
10207 fclose(stdin); fclose(stdout); fclose(stderr);
10208 close(0); close(1); close(2); /* close all fd's */
10209 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
10210 }
willy tarreaua1598082005-12-17 13:08:06 +010010211 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +010010212 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +010010213 }
10214
willy tarreau1c2ad212005-12-18 01:11:29 +010010215#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +010010216 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010217 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
10218 epoll_loop(POLL_LOOP_ACTION_RUN);
10219 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010220 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010221 }
10222 else {
willy tarreau64a3cc32005-12-18 01:13:11 +010010223 Warning("epoll() is not available. Using poll()/select() instead.\n");
10224 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010225 }
10226 }
10227#endif
10228
10229#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +010010230 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010231 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
10232 poll_loop(POLL_LOOP_ACTION_RUN);
10233 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010234 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010235 }
10236 else {
10237 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +010010238 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010239 }
10240 }
10241#endif
willy tarreau64a3cc32005-12-18 01:13:11 +010010242 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010243 if (select_loop(POLL_LOOP_ACTION_INIT)) {
10244 select_loop(POLL_LOOP_ACTION_RUN);
10245 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010246 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +010010247 }
10248 }
10249
willy tarreau0f7af912005-12-17 12:21:26 +010010250
willy tarreau12350152005-12-18 01:03:27 +010010251 /* Free all Hash Keys and all Hash elements */
10252 appsession_cleanup();
10253 /* Do some cleanup */
10254 deinit();
10255
willy tarreau0f7af912005-12-17 12:21:26 +010010256 exit(0);
10257}
willy tarreau12350152005-12-18 01:03:27 +010010258
10259#if defined(DEBUG_HASH)
10260static void print_table(const CHTbl *htbl) {
10261
10262 ListElmt *element;
10263 int i;
10264 appsess *asession;
10265
10266 /*****************************************************************************
10267 * *
10268 * Display the chained hash table. *
10269 * *
10270 *****************************************************************************/
10271
10272 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
10273
10274 for (i = 0; i < TBLSIZ; i++) {
10275 fprintf(stdout, "Bucket[%03d]\n", i);
10276
10277 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
10278 //fprintf(stdout, "%c", *(char *)list_data(element));
10279 asession = (appsess *)list_data(element);
10280 fprintf(stdout, "ELEM :%s:", asession->sessid);
10281 fprintf(stdout, " Server :%s: \n", asession->serverid);
10282 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
10283 }
10284
10285 fprintf(stdout, "\n");
10286 }
10287 return;
10288} /* end print_table */
10289#endif
10290
10291static int appsession_init(void)
10292{
10293 static int initialized = 0;
10294 int idlen;
10295 struct server *s;
10296 struct proxy *p = proxy;
10297
10298 if (!initialized) {
10299 if (!appsession_task_init()) {
10300 apools.sessid = NULL;
10301 apools.serverid = NULL;
10302 apools.ser_waste = 0;
10303 apools.ser_use = 0;
10304 apools.ser_msize = sizeof(void *);
10305 apools.ses_waste = 0;
10306 apools.ses_use = 0;
10307 apools.ses_msize = sizeof(void *);
10308 while (p) {
10309 s = p->srv;
10310 if (apools.ses_msize < p->appsession_len)
10311 apools.ses_msize = p->appsession_len;
10312 while (s) {
10313 idlen = strlen(s->id);
10314 if (apools.ser_msize < idlen)
10315 apools.ser_msize = idlen;
10316 s = s->next;
10317 }
10318 p = p->next;
10319 }
10320 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
10321 apools.ses_msize ++;
10322 }
10323 else {
10324 fprintf(stderr, "appsession_task_init failed\n");
10325 return -1;
10326 }
10327 initialized ++;
10328 }
10329 return 0;
10330}
10331
10332static int appsession_task_init(void)
10333{
10334 static int initialized = 0;
10335 struct task *t;
10336 if (!initialized) {
10337 if ((t = pool_alloc(task)) == NULL)
10338 return -1;
10339 t->next = t->prev = t->rqnext = NULL;
willy tarreau5e698ef2006-05-02 14:51:00 +020010340 t->wq = LIST_HEAD(wait_queue[0]);
willy tarreau12350152005-12-18 01:03:27 +010010341 t->state = TASK_IDLE;
10342 t->context = NULL;
10343 tv_delayfrom(&t->expire, &now, TBLCHKINT);
10344 task_queue(t);
10345 t->process = appsession_refresh;
10346 initialized ++;
10347 }
10348 return 0;
10349}
10350
10351static int appsession_refresh(struct task *t) {
10352 struct proxy *p = proxy;
10353 CHTbl *htbl;
10354 ListElmt *element, *last;
10355 int i;
10356 appsess *asession;
10357 void *data;
10358
10359 while (p) {
10360 if (p->appsession_name != NULL) {
10361 htbl = &p->htbl_proxy;
10362 /* if we ever give up the use of TBLSIZ, we need to change this */
10363 for (i = 0; i < TBLSIZ; i++) {
10364 last = NULL;
10365 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
10366 asession = (appsess *)list_data(element);
10367 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
10368 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
10369 int len;
10370 /*
10371 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
10372 */
10373 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
10374 asession->sessid, asession->serverid?asession->serverid:"(null)");
10375 write(1, trash, len);
10376 }
10377 /* delete the expired element from within the hash table */
10378 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
10379 && (htbl->table[i].destroy != NULL)) {
10380 htbl->table[i].destroy(data);
10381 }
10382 if (last == NULL) {/* patient lost his head, get a new one */
10383 element = list_head(&htbl->table[i]);
10384 if (element == NULL) break; /* no heads left, go to next patient */
10385 }
10386 else
10387 element = last;
10388 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
10389 else
10390 last = element;
10391 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
10392 }
10393 }
10394 p = p->next;
10395 }
10396 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
10397 return TBLCHKINT;
10398} /* end appsession_refresh */
10399
willy tarreau18a957c2006-04-12 19:26:23 +020010400
10401/*
10402 * Local variables:
10403 * c-indent-level: 4
10404 * c-basic-offset: 4
10405 * End:
10406 */