blob: 586978a0a3c0ec65ed450c43312ff9f8e0e0add1 [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 tarreauf76e6ca2006-05-21 21:09:55 +0200590 unsigned int maxconn, minconn; /* max # of active sessions (0 = unlimited), min# for dynamic limit. */
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 tarreauf76e6ca2006-05-21 21:09:55 +0200698 unsigned 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 tarreauf76e6ca2006-05-21 21:09:55 +0200700 unsigned 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 tarreauf76e6ca2006-05-21 21:09:55 +02001986/* returns the effective dynamic maxconn for a server, considering the minconn
1987 * and the proxy's usage relative to its saturation.
1988 */
1989static unsigned int srv_dynamic_maxconn(struct server *s) {
1990 return s->minconn ?
1991 ((s->maxconn * s->proxy->nbconn / s->proxy->maxconn) < s->minconn) ? s->minconn :
1992 (s->maxconn * s->proxy->nbconn / s->proxy->maxconn) : s->maxconn;
1993}
1994
willy tarreau59a6cc22006-05-12 01:29:08 +02001995/* returns 0 if nothing has to be done for server <s> regarding queued connections,
1996 * and non-zero otherwise. Suited for and if/else usage.
1997 */
1998static inline int may_dequeue_tasks(struct server *s, struct proxy *p) {
1999 return (s && (s->nbpend || p->nbpend) &&
willy tarreauf76e6ca2006-05-21 21:09:55 +02002000 (!s->maxconn || s->cur_sess < srv_dynamic_maxconn(s)) &&
2001 s->queue_mgt);
willy tarreau59a6cc22006-05-12 01:29:08 +02002002}
2003
2004
2005
willy tarreau18a957c2006-04-12 19:26:23 +02002006/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +01002007/* more specific functions ***************************************/
2008/*********************************************************************/
2009
2010/* some prototypes */
2011static int maintain_proxies(void);
2012
willy tarreaub952e1d2005-12-18 01:31:20 +01002013/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01002014 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
2015 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01002016static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01002017#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002018 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
2019#else
willy tarreaua1598082005-12-17 13:08:06 +01002020#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002021 return getsockname(fd, (struct sockaddr *)sa, salen);
2022#else
2023 return -1;
2024#endif
2025#endif
2026}
2027
2028/*
2029 * frees the context associated to a session. It must have been removed first.
2030 */
willy tarreaudfece232006-05-02 00:19:57 +02002031static void session_free(struct session *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02002032 if (s->pend_pos)
2033 pendconn_free(s->pend_pos);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002034 if (s->req)
2035 pool_free(buffer, s->req);
2036 if (s->rep)
2037 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01002038
2039 if (s->rsp_cap != NULL) {
2040 struct cap_hdr *h;
2041 for (h = s->proxy->rsp_cap; h; h = h->next) {
2042 if (s->rsp_cap[h->index] != NULL)
2043 pool_free_to(h->pool, s->rsp_cap[h->index]);
2044 }
2045 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
2046 }
2047 if (s->req_cap != NULL) {
2048 struct cap_hdr *h;
2049 for (h = s->proxy->req_cap; h; h = h->next) {
2050 if (s->req_cap[h->index] != NULL)
2051 pool_free_to(h->pool, s->req_cap[h->index]);
2052 }
2053 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
2054 }
2055
willy tarreaua1598082005-12-17 13:08:06 +01002056 if (s->logs.uri)
2057 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01002058 if (s->logs.cli_cookie)
2059 pool_free(capture, s->logs.cli_cookie);
2060 if (s->logs.srv_cookie)
2061 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01002062
willy tarreau5cbea6f2005-12-17 12:48:26 +01002063 pool_free(session, s);
2064}
2065
willy tarreau0f7af912005-12-17 12:21:26 +01002066
2067/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01002068 * This function recounts the number of usable active and backup servers for
2069 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002070 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01002071 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002072static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002073 struct server *srv;
2074
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002075 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002076 for (srv = px->srv; srv != NULL; srv = srv->next) {
2077 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002078 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002079 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002080 px->tot_wbck += srv->eweight + 1;
2081 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002082 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002083 px->tot_wact += srv->eweight + 1;
2084 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01002085 }
2086 }
2087}
2088
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002089/* This function recomputes the server map for proxy px. It
2090 * relies on px->tot_wact and px->tot_wbck, so it must be
2091 * called after recount_servers(). It also expects px->srv_map
2092 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01002093 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002094static void recalc_server_map(struct proxy *px) {
2095 int o, tot, flag;
2096 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01002097
willy tarreau4c8c2b52006-03-24 19:36:41 +01002098 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002099 flag = SRV_RUNNING;
2100 tot = px->tot_wact;
2101 } else if (px->srv_bck) {
2102 flag = SRV_RUNNING | SRV_BACKUP;
2103 if (px->options & PR_O_USE_ALL_BK)
2104 tot = px->tot_wbck;
2105 else
2106 tot = 1; /* the first server is enough */
2107 } else {
2108 px->srv_map_sz = 0;
2109 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002110 }
Willy TARREAU3481c462006-03-01 22:37:57 +01002111
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002112 /* this algorithm gives priority to the first server, which means that
2113 * it will respect the declaration order for equivalent weights, and
2114 * that whatever the weights, the first server called will always be
2115 * the first declard. This is an important asumption for the backup
2116 * case, where we want the first server only.
2117 */
2118 for (cur = px->srv; cur; cur = cur->next)
2119 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002120
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002121 for (o = 0; o < tot; o++) {
2122 int max = 0;
2123 best = NULL;
2124 for (cur = px->srv; cur; cur = cur->next) {
2125 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
2126 int v;
2127
2128 /* If we are forced to return only one server, we don't want to
2129 * go further, because we would return the wrong one due to
2130 * divide overflow.
2131 */
2132 if (tot == 1) {
2133 best = cur;
2134 break;
2135 }
2136
2137 cur->wscore += cur->eweight + 1;
2138 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
2139 if (best == NULL || v > max) {
2140 max = v;
2141 best = cur;
2142 }
2143 }
2144 }
2145 px->srv_map[o] = best;
2146 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002147 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002148 px->srv_map_sz = tot;
2149}
Willy TARREAU3481c462006-03-01 22:37:57 +01002150
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002151/*
willy tarreau898db9d2006-04-12 20:29:08 +02002152 * This function tries to find a running server with free connection slots for
2153 * the proxy <px> following the round-robin method.
2154 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2155 * to point to the next server. If no valid server is found, NULL is returned.
2156 */
2157static inline struct server *get_server_rr_with_conns(struct proxy *px) {
2158 int newidx;
2159 struct server *srv;
2160
2161 if (px->srv_map_sz == 0)
2162 return NULL;
2163
2164 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2165 px->srv_rr_idx = 0;
2166 newidx = px->srv_rr_idx;
2167
2168 do {
2169 srv = px->srv_map[newidx++];
willy tarreauf76e6ca2006-05-21 21:09:55 +02002170 if (!srv->maxconn || srv->cur_sess < srv_dynamic_maxconn(srv)) {
willy tarreau898db9d2006-04-12 20:29:08 +02002171 px->srv_rr_idx = newidx;
2172 return srv;
2173 }
2174 if (newidx == px->srv_map_sz)
2175 newidx = 0;
2176 } while (newidx != px->srv_rr_idx);
2177
2178 return NULL;
2179}
2180
2181
2182/*
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002183 * This function tries to find a running server for the proxy <px> following
willy tarreau898db9d2006-04-12 20:29:08 +02002184 * the round-robin method.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002185 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2186 * to point to the next server. If no valid server is found, NULL is returned.
2187 */
2188static inline struct server *get_server_rr(struct proxy *px) {
2189 if (px->srv_map_sz == 0)
2190 return NULL;
2191
2192 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2193 px->srv_rr_idx = 0;
2194 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01002195}
2196
willy tarreau62084d42006-03-24 18:57:41 +01002197
2198/*
willy tarreau1a3442d2006-03-24 21:03:20 +01002199 * This function tries to find a running server for the proxy <px> following
2200 * the source hash method. Depending on the number of active/backup servers,
2201 * it will either look for active servers, or for backup servers.
2202 * If any server is found, it will be returned. If no valid server is found,
2203 * NULL is returned.
2204 */
2205static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002206 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01002207
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002208 if (px->srv_map_sz == 0)
2209 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01002210
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002211 l = h = 0;
willy tarreaucd655352006-04-29 12:11:46 +02002212 if (px->srv_act > 1 || (px->srv_act == 0 && px->srv_bck > 1)) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002213 while ((l + sizeof (int)) <= len) {
2214 h ^= ntohl(*(unsigned int *)(&addr[l]));
2215 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01002216 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002217 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01002218 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002219 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01002220}
2221
2222
2223/*
willy tarreaudfece232006-05-02 00:19:57 +02002224 * This function marks the session as 'assigned' in direct or dispatch modes,
2225 * or tries to assign one in balance mode, according to the algorithm. It does
2226 * nothing if the session had already been assigned a server.
2227 *
2228 * It may return :
willy tarreau000375f2006-05-09 23:15:58 +02002229 * SRV_STATUS_OK if everything is OK. s->srv will be valid.
2230 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
2231 * SRV_STATUS_FULL if all servers are saturated. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002232 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2233 *
2234 * Upon successful return, the session flag SN_ASSIGNED to indicate that it does
2235 * not need to be called anymore. This usually means that s->srv can be trusted
2236 * in balance and direct modes. This flag is not cleared, so it's to the caller
2237 * to clear it if required (eg: redispatch).
2238 *
willy tarreau0f7af912005-12-17 12:21:26 +01002239 */
willy tarreau0f7af912005-12-17 12:21:26 +01002240
willy tarreaudfece232006-05-02 00:19:57 +02002241int assign_server(struct session *s) {
willy tarreau12350152005-12-18 01:03:27 +01002242#ifdef DEBUG_FULL
willy tarreaudfece232006-05-02 00:19:57 +02002243 fprintf(stderr,"assign_server : s=%p\n",s);
willy tarreau12350152005-12-18 01:03:27 +01002244#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002245
willy tarreaudfece232006-05-02 00:19:57 +02002246 if (s->pend_pos)
2247 return SRV_STATUS_INTERNAL;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002248
willy tarreaudfece232006-05-02 00:19:57 +02002249 if (!(s->flags & SN_ASSIGNED)) {
2250 if ((s->proxy->options & PR_O_BALANCE) && !(s->flags & SN_DIRECT)) {
2251 if (!s->proxy->srv_act && !s->proxy->srv_bck)
2252 return SRV_STATUS_NOSRV;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002253
willy tarreaudfece232006-05-02 00:19:57 +02002254 if (s->proxy->options & PR_O_BALANCE_RR) {
2255 s->srv = get_server_rr_with_conns(s->proxy);
2256 if (!s->srv)
2257 return SRV_STATUS_FULL;
2258 }
2259 else if (s->proxy->options & PR_O_BALANCE_SH) {
2260 int len;
2261
2262 if (s->cli_addr.ss_family == AF_INET)
2263 len = 4;
2264 else if (s->cli_addr.ss_family == AF_INET6)
2265 len = 16;
2266 else /* unknown IP family */
2267 return SRV_STATUS_INTERNAL;
2268
2269 s->srv = get_server_sh(s->proxy,
2270 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2271 len);
2272 }
2273 else /* unknown balancing algorithm */
2274 return SRV_STATUS_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002275 }
willy tarreaudfece232006-05-02 00:19:57 +02002276 s->flags |= SN_ASSIGNED;
2277 }
2278 return SRV_STATUS_OK;
2279}
willy tarreau1a3442d2006-03-24 21:03:20 +01002280
willy tarreaudfece232006-05-02 00:19:57 +02002281/*
2282 * This function assigns a server address to a session, and sets SN_ADDR_SET.
2283 * The address is taken from the currently assigned server, or from the
2284 * dispatch or transparent address.
2285 *
2286 * It may return :
2287 * SRV_STATUS_OK if everything is OK.
2288 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2289 *
2290 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
2291 * not cleared, so it's to the caller to clear it if required.
2292 *
2293 */
2294int assign_server_address(struct session *s) {
2295#ifdef DEBUG_FULL
2296 fprintf(stderr,"assign_server_address : s=%p\n",s);
2297#endif
2298
2299 if (s->flags & SN_DIRECT || s->proxy->options & PR_O_BALANCE) {
2300 /* A server is necessarily known for this session */
2301 if (!(s->flags & SN_ASSIGNED))
2302 return SRV_STATUS_INTERNAL;
2303
2304 s->srv_addr = s->srv->addr;
willy tarreau1a3442d2006-03-24 21:03:20 +01002305
willy tarreaudfece232006-05-02 00:19:57 +02002306 /* if this server remaps proxied ports, we'll use
2307 * the port the client connected to with an offset. */
2308 if (s->srv->state & SRV_MAPPORTS) {
2309 struct sockaddr_in sockname;
2310 socklen_t namelen = sizeof(sockname);
2311
2312 if (!(s->proxy->options & PR_O_TRANSP) ||
2313 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2314 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2315 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
willy tarreau1a3442d2006-03-24 21:03:20 +01002316 }
willy tarreau0f7af912005-12-17 12:21:26 +01002317 }
willy tarreaua1598082005-12-17 13:08:06 +01002318 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002319 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002320 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002321 }
2322 else if (s->proxy->options & PR_O_TRANSP) {
2323 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002324 socklen_t salen = sizeof(s->srv_addr);
2325
willy tarreau5cbea6f2005-12-17 12:48:26 +01002326 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2327 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaudfece232006-05-02 00:19:57 +02002328 return SRV_STATUS_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002329 }
2330 }
willy tarreau0f7af912005-12-17 12:21:26 +01002331
willy tarreaudfece232006-05-02 00:19:57 +02002332 s->flags |= SN_ADDR_SET;
2333 return SRV_STATUS_OK;
2334}
willy tarreaua41a8b42005-12-17 14:02:24 +01002335
willy tarreaudfece232006-05-02 00:19:57 +02002336/* This function assigns a server to session <s> if required, and can add the
2337 * connection to either the assigned server's queue or to the proxy's queue.
2338 *
2339 * Returns :
2340 *
2341 * SRV_STATUS_OK if everything is OK.
willy tarreau000375f2006-05-09 23:15:58 +02002342 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002343 * SRV_STATUS_QUEUED if the connection has been queued.
2344 * SRV_STATUS_FULL if the server(s) is/are saturated and the
2345 * connection could not be queued.
2346 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2347 *
2348 */
2349int assign_server_and_queue(struct session *s) {
2350 struct pendconn *p;
2351 int err;
2352
2353 if (s->pend_pos)
2354 return SRV_STATUS_INTERNAL;
2355
2356 if (s->flags & SN_ASSIGNED) {
2357 /* a server does not need to be assigned, perhaps because we're in
2358 * direct mode, or in dispatch or transparent modes where the server
2359 * is not needed.
2360 */
2361 if (s->srv &&
willy tarreauf76e6ca2006-05-21 21:09:55 +02002362 s->srv->maxconn && s->srv->cur_sess >= srv_dynamic_maxconn(s->srv)) {
willy tarreaudfece232006-05-02 00:19:57 +02002363 p = pendconn_add(s);
2364 if (p)
2365 return SRV_STATUS_QUEUED;
2366 else
2367 return SRV_STATUS_FULL;
2368 }
2369 return SRV_STATUS_OK;
2370 }
2371
2372 /* a server needs to be assigned */
2373 err = assign_server(s);
2374 switch (err) {
2375 case SRV_STATUS_OK:
2376 /* in balance mode, we might have servers with connection limits */
willy tarreauf76e6ca2006-05-21 21:09:55 +02002377 if (s->srv &&
2378 s->srv->maxconn && s->srv->cur_sess >= srv_dynamic_maxconn(s->srv)) {
willy tarreaudfece232006-05-02 00:19:57 +02002379 p = pendconn_add(s);
2380 if (p)
2381 return SRV_STATUS_QUEUED;
2382 else
2383 return SRV_STATUS_FULL;
2384 }
2385 return SRV_STATUS_OK;
2386
2387 case SRV_STATUS_FULL:
2388 /* queue this session into the proxy's queue */
2389 p = pendconn_add(s);
2390 if (p)
2391 return SRV_STATUS_QUEUED;
2392 else
2393 return SRV_STATUS_FULL;
2394
2395 case SRV_STATUS_NOSRV:
2396 case SRV_STATUS_INTERNAL:
2397 return err;
2398 default:
2399 return SRV_STATUS_INTERNAL;
willy tarreaua41a8b42005-12-17 14:02:24 +01002400 }
willy tarreaudfece232006-05-02 00:19:57 +02002401}
2402
2403
2404/*
2405 * This function initiates a connection to the server assigned to this session
2406 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
2407 * It can return one of :
2408 * - SN_ERR_NONE if everything's OK
2409 * - SN_ERR_SRVTO if there are no more servers
2410 * - SN_ERR_SRVCL if the connection was refused by the server
2411 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
2412 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
2413 * - SN_ERR_INTERNAL for any other purely internal errors
2414 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
2415 */
2416int connect_server(struct session *s) {
2417 int fd, err;
2418
2419 if (!(s->flags & SN_ADDR_SET)) {
2420 err = assign_server_address(s);
2421 if (err != SRV_STATUS_OK)
2422 return SN_ERR_INTERNAL;
2423 }
willy tarreaua41a8b42005-12-17 14:02:24 +01002424
willy tarreau0f7af912005-12-17 12:21:26 +01002425 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002426 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002427
2428 if (errno == ENFILE)
2429 send_log(s->proxy, LOG_EMERG,
2430 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2431 s->proxy->id, maxfd);
2432 else if (errno == EMFILE)
2433 send_log(s->proxy, LOG_EMERG,
2434 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2435 s->proxy->id, maxfd);
2436 else if (errno == ENOBUFS || errno == ENOMEM)
2437 send_log(s->proxy, LOG_EMERG,
2438 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2439 s->proxy->id, maxfd);
2440 /* this is a resource error */
2441 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002442 }
2443
willy tarreau9fe663a2005-12-17 13:02:59 +01002444 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002445 /* do not log anything there, it's a normal condition when this option
2446 * is used to serialize connections to a server !
2447 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002448 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2449 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002450 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002451 }
2452
willy tarreau0f7af912005-12-17 12:21:26 +01002453 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2454 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002455 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002456 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002457 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002458 }
2459
willy tarreaub952e1d2005-12-18 01:31:20 +01002460 if (s->proxy->options & PR_O_TCP_SRV_KA)
2461 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2462
willy tarreau0174f312005-12-18 01:02:42 +01002463 /* allow specific binding :
2464 * - server-specific at first
2465 * - proxy-specific next
2466 */
2467 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2468 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2469 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2470 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2471 s->proxy->id, s->srv->id);
2472 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002473 send_log(s->proxy, LOG_EMERG,
2474 "Cannot bind to source address before connect() for server %s/%s.\n",
2475 s->proxy->id, s->srv->id);
2476 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002477 }
2478 }
2479 else if (s->proxy->options & PR_O_BIND_SRC) {
2480 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2481 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2482 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2483 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002484 send_log(s->proxy, LOG_EMERG,
2485 "Cannot bind to source address before connect() for server %s/%s.\n",
2486 s->proxy->id, s->srv->id);
2487 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002488 }
willy tarreaua1598082005-12-17 13:08:06 +01002489 }
2490
willy tarreaub1285d52005-12-18 01:20:14 +01002491 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2492 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2493
2494 if (errno == EAGAIN || errno == EADDRINUSE) {
2495 char *msg;
2496 if (errno == EAGAIN) /* no free ports left, try again later */
2497 msg = "no free ports";
2498 else
2499 msg = "local address already in use";
2500
2501 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002502 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002503 send_log(s->proxy, LOG_EMERG,
2504 "Connect() failed for server %s/%s: %s.\n",
2505 s->proxy->id, s->srv->id, msg);
2506 return SN_ERR_RESOURCE;
2507 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002508 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002509 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002510 return SN_ERR_SRVTO;
2511 } else {
2512 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002513 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002514 close(fd);
2515 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002516 }
2517 }
2518
willy tarreau5cbea6f2005-12-17 12:48:26 +01002519 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002520 fdtab[fd].read = &event_srv_read;
2521 fdtab[fd].write = &event_srv_write;
2522 fdtab[fd].state = FD_STCONN; /* connection in progress */
2523
2524 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002525#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2526 if (PrevReadEvent) {
2527 assert(!(FD_ISSET(fd, PrevReadEvent)));
2528 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2529 }
2530#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002531
2532 fd_insert(fd);
willy tarreaucb406512006-05-18 00:52:35 +02002533 if (s->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02002534 s->srv->cur_sess++;
willy tarreaucb406512006-05-18 00:52:35 +02002535 if (s->srv->cur_sess > s->srv->cur_sess_max)
2536 s->srv->cur_sess_max = s->srv->cur_sess;
2537 }
willy tarreau0f7af912005-12-17 12:21:26 +01002538
2539 if (s->proxy->contimeout)
2540 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2541 else
2542 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002543 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002544}
2545
2546/*
2547 * this function is called on a read event from a client socket.
2548 * It returns 0.
2549 */
2550int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002551 struct task *t = fdtab[fd].owner;
2552 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002553 struct buffer *b = s->req;
2554 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002555
willy tarreau12350152005-12-18 01:03:27 +01002556#ifdef DEBUG_FULL
2557 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2558#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002559
willy tarreau0f7af912005-12-17 12:21:26 +01002560 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002561#ifdef FILL_BUFFERS
2562 while (1)
2563#else
2564 do
2565#endif
2566 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002567 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2568 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002569 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002570 }
2571 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002572 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002573 }
2574 else {
2575 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002576 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2577 * since it means that the rewrite protection has been removed. This
2578 * implies that the if statement can be removed.
2579 */
2580 if (max > b->rlim - b->data)
2581 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002582 }
2583
2584 if (max == 0) { /* not anymore room to store data */
2585 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002586 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002587 }
2588
willy tarreau3242e862005-12-17 12:27:53 +01002589#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002590 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002591 int skerr;
2592 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002593
willy tarreau5cbea6f2005-12-17 12:48:26 +01002594 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2595 if (skerr)
2596 ret = -1;
2597 else
2598 ret = recv(fd, b->r, max, 0);
2599 }
willy tarreau3242e862005-12-17 12:27:53 +01002600#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002601 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002602#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002603 if (ret > 0) {
2604 b->r += ret;
2605 b->l += ret;
2606 s->res_cr = RES_DATA;
2607
2608 if (b->r == b->data + BUFSIZE) {
2609 b->r = b->data; /* wrap around the buffer */
2610 }
willy tarreaua1598082005-12-17 13:08:06 +01002611
2612 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002613 /* we hope to read more data or to get a close on next round */
2614 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002615 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002616 else if (ret == 0) {
2617 s->res_cr = RES_NULL;
2618 break;
2619 }
2620 else if (errno == EAGAIN) {/* ignore EAGAIN */
2621 break;
2622 }
2623 else {
2624 s->res_cr = RES_ERROR;
2625 fdtab[fd].state = FD_STERROR;
2626 break;
2627 }
2628 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002629#ifndef FILL_BUFFERS
2630 while (0);
2631#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002632 }
2633 else {
2634 s->res_cr = RES_ERROR;
2635 fdtab[fd].state = FD_STERROR;
2636 }
2637
willy tarreau5cbea6f2005-12-17 12:48:26 +01002638 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002639 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002640 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2641 else
2642 tv_eternity(&s->crexpire);
2643
2644 task_wakeup(&rq, t);
2645 }
willy tarreau0f7af912005-12-17 12:21:26 +01002646
willy tarreau0f7af912005-12-17 12:21:26 +01002647 return 0;
2648}
2649
2650
2651/*
2652 * this function is called on a read event from a server socket.
2653 * It returns 0.
2654 */
2655int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002656 struct task *t = fdtab[fd].owner;
2657 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002658 struct buffer *b = s->rep;
2659 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002660
willy tarreau12350152005-12-18 01:03:27 +01002661#ifdef DEBUG_FULL
2662 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2663#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002664
willy tarreau0f7af912005-12-17 12:21:26 +01002665 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002666#ifdef FILL_BUFFERS
2667 while (1)
2668#else
2669 do
2670#endif
2671 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002672 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2673 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002674 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002675 }
2676 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002677 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002678 }
2679 else {
2680 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002681 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2682 * since it means that the rewrite protection has been removed. This
2683 * implies that the if statement can be removed.
2684 */
2685 if (max > b->rlim - b->data)
2686 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002687 }
2688
2689 if (max == 0) { /* not anymore room to store data */
2690 FD_CLR(fd, StaticReadEvent);
2691 break;
2692 }
2693
willy tarreau3242e862005-12-17 12:27:53 +01002694#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002695 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002696 int skerr;
2697 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002698
willy tarreau5cbea6f2005-12-17 12:48:26 +01002699 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2700 if (skerr)
2701 ret = -1;
2702 else
2703 ret = recv(fd, b->r, max, 0);
2704 }
willy tarreau3242e862005-12-17 12:27:53 +01002705#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002706 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002707#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002708 if (ret > 0) {
2709 b->r += ret;
2710 b->l += ret;
2711 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002712
willy tarreau5cbea6f2005-12-17 12:48:26 +01002713 if (b->r == b->data + BUFSIZE) {
2714 b->r = b->data; /* wrap around the buffer */
2715 }
willy tarreaua1598082005-12-17 13:08:06 +01002716
2717 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002718 /* we hope to read more data or to get a close on next round */
2719 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002720 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002721 else if (ret == 0) {
2722 s->res_sr = RES_NULL;
2723 break;
2724 }
2725 else if (errno == EAGAIN) {/* ignore EAGAIN */
2726 break;
2727 }
2728 else {
2729 s->res_sr = RES_ERROR;
2730 fdtab[fd].state = FD_STERROR;
2731 break;
2732 }
2733 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002734#ifndef FILL_BUFFERS
2735 while (0);
2736#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002737 }
2738 else {
2739 s->res_sr = RES_ERROR;
2740 fdtab[fd].state = FD_STERROR;
2741 }
2742
willy tarreau5cbea6f2005-12-17 12:48:26 +01002743 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002744 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002745 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2746 else
2747 tv_eternity(&s->srexpire);
2748
2749 task_wakeup(&rq, t);
2750 }
willy tarreau0f7af912005-12-17 12:21:26 +01002751
willy tarreau0f7af912005-12-17 12:21:26 +01002752 return 0;
2753}
2754
2755/*
2756 * this function is called on a write event from a client socket.
2757 * It returns 0.
2758 */
2759int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002760 struct task *t = fdtab[fd].owner;
2761 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002762 struct buffer *b = s->rep;
2763 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002764
willy tarreau12350152005-12-18 01:03:27 +01002765#ifdef DEBUG_FULL
2766 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2767#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002768
2769 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002770 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002771 // max = BUFSIZE; BUG !!!!
2772 max = 0;
2773 }
2774 else if (b->r > b->w) {
2775 max = b->r - b->w;
2776 }
2777 else
2778 max = b->data + BUFSIZE - b->w;
2779
willy tarreau0f7af912005-12-17 12:21:26 +01002780 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002781 if (max == 0) {
2782 s->res_cw = RES_NULL;
2783 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002784 tv_eternity(&s->cwexpire);
2785 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002786 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002787 }
2788
willy tarreau3242e862005-12-17 12:27:53 +01002789#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002790 {
2791 int skerr;
2792 socklen_t lskerr = sizeof(skerr);
2793
2794 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2795 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002796 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002797 else
willy tarreau3242e862005-12-17 12:27:53 +01002798 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002799 }
willy tarreau3242e862005-12-17 12:27:53 +01002800#else
willy tarreau0f7af912005-12-17 12:21:26 +01002801 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002802#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002803
2804 if (ret > 0) {
2805 b->l -= ret;
2806 b->w += ret;
2807
2808 s->res_cw = RES_DATA;
2809
2810 if (b->w == b->data + BUFSIZE) {
2811 b->w = b->data; /* wrap around the buffer */
2812 }
2813 }
2814 else if (ret == 0) {
2815 /* nothing written, just make as if we were never called */
2816// s->res_cw = RES_NULL;
2817 return 0;
2818 }
2819 else if (errno == EAGAIN) /* ignore EAGAIN */
2820 return 0;
2821 else {
2822 s->res_cw = RES_ERROR;
2823 fdtab[fd].state = FD_STERROR;
2824 }
2825 }
2826 else {
2827 s->res_cw = RES_ERROR;
2828 fdtab[fd].state = FD_STERROR;
2829 }
2830
willy tarreaub1ff9db2005-12-17 13:51:03 +01002831 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002832 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002833 /* FIXME: to prevent the client from expiring read timeouts during writes,
2834 * we refresh it. A solution would be to merge read+write timeouts into a
2835 * unique one, although that needs some study particularly on full-duplex
2836 * TCP connections. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002837 s->crexpire = s->cwexpire;
2838 }
willy tarreau0f7af912005-12-17 12:21:26 +01002839 else
2840 tv_eternity(&s->cwexpire);
2841
willy tarreau5cbea6f2005-12-17 12:48:26 +01002842 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002843 return 0;
2844}
2845
2846
2847/*
2848 * this function is called on a write event from a server socket.
2849 * It returns 0.
2850 */
2851int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002852 struct task *t = fdtab[fd].owner;
2853 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002854 struct buffer *b = s->req;
2855 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002856
willy tarreau12350152005-12-18 01:03:27 +01002857#ifdef DEBUG_FULL
2858 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2859#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002860
2861 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002862 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002863 // max = BUFSIZE; BUG !!!!
2864 max = 0;
2865 }
2866 else if (b->r > b->w) {
2867 max = b->r - b->w;
2868 }
2869 else
2870 max = b->data + BUFSIZE - b->w;
2871
willy tarreau0f7af912005-12-17 12:21:26 +01002872 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002873 if (max == 0) {
2874 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002875 if (s->srv_state == SV_STCONN) {
2876 int skerr;
2877 socklen_t lskerr = sizeof(skerr);
2878 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2879 if (skerr) {
2880 s->res_sw = RES_ERROR;
2881 fdtab[fd].state = FD_STERROR;
2882 task_wakeup(&rq, t);
2883 tv_eternity(&s->swexpire);
2884 FD_CLR(fd, StaticWriteEvent);
2885 return 0;
2886 }
2887 }
2888
willy tarreau0f7af912005-12-17 12:21:26 +01002889 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002890 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002891 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002892 tv_eternity(&s->swexpire);
2893 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002894 return 0;
2895 }
2896
willy tarreau3242e862005-12-17 12:27:53 +01002897#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002898 {
2899 int skerr;
2900 socklen_t lskerr = sizeof(skerr);
2901 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2902 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002903 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002904 else
willy tarreau3242e862005-12-17 12:27:53 +01002905 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002906 }
willy tarreau3242e862005-12-17 12:27:53 +01002907#else
willy tarreau0f7af912005-12-17 12:21:26 +01002908 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002909#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002910 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002911 if (ret > 0) {
2912 b->l -= ret;
2913 b->w += ret;
2914
2915 s->res_sw = RES_DATA;
2916
2917 if (b->w == b->data + BUFSIZE) {
2918 b->w = b->data; /* wrap around the buffer */
2919 }
2920 }
2921 else if (ret == 0) {
2922 /* nothing written, just make as if we were never called */
2923 // s->res_sw = RES_NULL;
2924 return 0;
2925 }
2926 else if (errno == EAGAIN) /* ignore EAGAIN */
2927 return 0;
2928 else {
2929 s->res_sw = RES_ERROR;
2930 fdtab[fd].state = FD_STERROR;
2931 }
2932 }
2933 else {
2934 s->res_sw = RES_ERROR;
2935 fdtab[fd].state = FD_STERROR;
2936 }
2937
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002938 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2939 * otherwise it could loop indefinitely !
2940 */
2941 if (s->srv_state != SV_STCONN) {
2942 if (s->proxy->srvtimeout) {
2943 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002944 /* FIXME: to prevent the server from expiring read timeouts during writes,
2945 * we refresh it. A solution would be to merge read+write+connect timeouts
2946 * into a unique one since we don't mind expiring on read or write, and none
2947 * of them is enabled while waiting for connect(), although that needs some
2948 * study particularly on full-duplex TCP connections. */
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002949 s->srexpire = s->swexpire;
2950 }
2951 else
2952 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002953 }
willy tarreau0f7af912005-12-17 12:21:26 +01002954
willy tarreau5cbea6f2005-12-17 12:48:26 +01002955 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002956 return 0;
2957}
2958
2959
willy tarreaue0331262006-05-15 03:02:46 +02002960/* returns 1 if the buffer is empty, 0 otherwise */
2961static inline int buffer_isempty(struct buffer *buf) {
2962 return buf->l == 0;
2963}
2964
2965
2966/* returns 1 if the buffer is full, 0 otherwise */
2967static inline int buffer_isfull(struct buffer *buf) {
2968 return buf->l == BUFSIZE;
2969}
2970
2971
2972/* flushes any content from buffer <buf> */
2973void buffer_flush(struct buffer *buf) {
2974 buf->r = buf->h = buf->lr = buf->w = buf->data;
2975 buf->l = 0;
2976}
2977
2978
2979/* returns the maximum number of bytes writable at once in this buffer */
2980int buffer_max(struct buffer *buf) {
willy tarreaucb406512006-05-18 00:52:35 +02002981 if (buf->l == BUFSIZE)
2982 return 0;
2983 else if (buf->r >= buf->w)
willy tarreaue0331262006-05-15 03:02:46 +02002984 return buf->data + BUFSIZE - buf->r;
2985 else
2986 return buf->w - buf->r;
2987}
2988
2989
willy tarreau0f7af912005-12-17 12:21:26 +01002990/*
willy tarreaue0331262006-05-15 03:02:46 +02002991 * Tries to realign the given buffer, and returns how many bytes can be written
2992 * there at once without overwriting anything.
2993 */
2994int buffer_realign(struct buffer *buf) {
2995 if (buf->l == 0) {
2996 /* let's realign the buffer to optimize I/O */
willy tarreaucb406512006-05-18 00:52:35 +02002997 buf->r = buf->w = buf->h = buf->lr = buf->data;
willy tarreaue0331262006-05-15 03:02:46 +02002998 }
2999 return buffer_max(buf);
3000}
3001
3002
3003/* writes <len> bytes from message <msg> to buffer <buf>. Returns 0 in case of
3004 * success, or the number of bytes available otherwise.
willy tarreau1f431b52006-05-21 14:46:15 +02003005 * FIXME-20060521: handle unaligned data.
willy tarreaue0331262006-05-15 03:02:46 +02003006 */
3007int buffer_write(struct buffer *buf, const char *msg, int len) {
3008 int max;
3009
willy tarreaucb406512006-05-18 00:52:35 +02003010 max = buffer_realign(buf);
willy tarreaue0331262006-05-15 03:02:46 +02003011
3012 if (len > max)
3013 return max;
3014
3015 memcpy(buf->r, msg, len);
3016 buf->l += len;
3017 buf->r += len;
3018 if (buf->r == buf->data + BUFSIZE)
willy tarreaucb406512006-05-18 00:52:35 +02003019 buf->r = buf->data;
willy tarreaue0331262006-05-15 03:02:46 +02003020 return 0;
3021}
3022
3023
3024/*
willy tarreaue39cd132005-12-17 13:00:18 +01003025 * returns a message to the client ; the connection is shut down for read,
3026 * and the request is cleared so that no server connection can be initiated.
3027 * The client must be in a valid state for this (HEADER, DATA ...).
3028 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01003029 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01003030 */
3031void client_retnclose(struct session *s, int len, const char *msg) {
3032 FD_CLR(s->cli_fd, StaticReadEvent);
3033 FD_SET(s->cli_fd, StaticWriteEvent);
3034 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01003035 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01003036 shutdown(s->cli_fd, SHUT_RD);
3037 s->cli_state = CL_STSHUTR;
willy tarreaue0331262006-05-15 03:02:46 +02003038 buffer_flush(s->rep);
3039 buffer_write(s->rep, msg, len);
willy tarreaue39cd132005-12-17 13:00:18 +01003040 s->req->l = 0;
3041}
3042
3043
3044/*
3045 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01003046 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01003047 */
3048void client_return(struct session *s, int len, const char *msg) {
willy tarreaue0331262006-05-15 03:02:46 +02003049 buffer_flush(s->rep);
3050 buffer_write(s->rep, msg, len);
willy tarreaue39cd132005-12-17 13:00:18 +01003051 s->req->l = 0;
3052}
3053
willy tarreaue0331262006-05-15 03:02:46 +02003054/*
3055 * Produces data for the session <s> depending on its source. Expects to be
3056 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3057 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3058 * session, which it uses to keep on being called when there is free space in
3059 * the buffer, of simply by letting an empty buffer upon return. It returns 1
3060 * if it changes the session state from CL_STSHUTR, otherwise 0.
3061 */
3062int produce_content(struct session *s) {
3063 struct buffer *rep = s->rep;
3064 struct proxy *px;
3065 struct server *sv;
willy tarreaucb406512006-05-18 00:52:35 +02003066 int msglen;
willy tarreaue0331262006-05-15 03:02:46 +02003067
3068 if (s->data_source == DATA_SRC_NONE) {
3069 s->flags &= ~SN_SELF_GEN;
3070 return 1;
3071 }
3072 else if (s->data_source == DATA_SRC_STATS) {
willy tarreau1f431b52006-05-21 14:46:15 +02003073 msglen = 0;
3074
3075 if (s->data_state == DATA_ST_INIT) { /* the function had not been called yet */
3076 unsigned int up;
3077
willy tarreaue0331262006-05-15 03:02:46 +02003078 s->flags |= SN_SELF_GEN; // more data will follow
willy tarreau1f431b52006-05-21 14:46:15 +02003079
3080 /* send the start of the HTTP response */
3081 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003082 "HTTP/1.0 200 OK\r\n"
3083 "Cache-Control: no-cache\r\n"
3084 "Connection: close\r\n"
3085 "\r\n\r\n");
3086
3087 s->logs.status = 200;
3088 client_retnclose(s, msglen, trash); // send the start of the response.
willy tarreau1f431b52006-05-21 14:46:15 +02003089 msglen = 0;
3090
willy tarreaue0331262006-05-15 03:02:46 +02003091 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
3092 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
3093 if (!(s->flags & SN_FINST_MASK))
3094 s->flags |= SN_FINST_R;
3095
3096 /* WARNING! This must fit in the first buffer !!! */
willy tarreau1f431b52006-05-21 14:46:15 +02003097 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003098 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
3099 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
3100 "<style type=\"text/css\"><!--\n"
3101 "body {"
3102 " font-family: helvetica, arial;"
3103 " font-size: 12px;"
3104 " font-weight: normal;"
3105 " color: black;"
3106 " background: white;"
3107 "}\n"
3108 "td {"
3109 " font-size: 12px;"
willy tarreaucb406512006-05-18 00:52:35 +02003110 " align: center;"
willy tarreaue0331262006-05-15 03:02:46 +02003111 "}\n"
3112 "h1 {"
3113 " font-size: xx-large;"
3114 " margin-bottom: 0.5em;"
3115 "}\n"
3116 "h2 {"
3117 " font-family: helvetica, arial;"
3118 " font-size: x-large;"
3119 " font-weight: bold;"
3120 " font-style: italic;"
3121 " color: #6020a0;"
3122 " margin-top: 0em;"
3123 " margin-bottom: 0em;"
3124 "}\n"
3125 "h3 {"
3126 " font-family: helvetica, arial;"
3127 " font-size: 16px;"
3128 " font-weight: bold;"
3129 " color: #b00040;"
3130 " background: #e8e8d0;"
3131 " margin-top: 0em;"
3132 " margin-bottom: 0em;"
3133 "}\n"
3134 "li {"
3135 " margin-top: 0.25em;"
3136 " margin-right: 2em;"
3137 "}\n"
3138 ".hr {"
3139 " margin-top: 0.25em;"
3140 " border-color: black;"
3141 " border-bottom-style: solid;"
willy tarreaucb406512006-05-18 00:52:35 +02003142 "}\n"
3143 "table.tbl { border-collapse: collapse; border-width: 1px; border-style: solid; border-color: gray;}\n"
3144 "table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; border-color: gray; }\n"
3145 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray; }\n"
3146 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
3147 "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 +02003148 "-->"
3149 "</style></head>");
3150
willy tarreaucb406512006-05-18 00:52:35 +02003151 if (buffer_write(rep, trash, msglen) != 0)
3152 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003153 msglen = 0;
willy tarreaue0331262006-05-15 03:02:46 +02003154
3155 up = (now.tv_sec - start_date.tv_sec);
3156
3157 /* WARNING! this has to fit the first packet too */
willy tarreau1f431b52006-05-21 14:46:15 +02003158 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003159 "<body><h1>" PRODUCT_NAME "</h1>\n"
3160 "<h2>Statistics Report for pid %d</h2>\n"
3161 "<hr width=\"100%%\" class=\"hr\">\n"
willy tarreau338be832006-05-21 08:58:06 +02003162 "<h3>&gt; General process information</h3>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003163 "<table border=0><tr><td align=\"left\">\n"
willy tarreaue0331262006-05-15 03:02:46 +02003164 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
3165 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
willy tarreau338be832006-05-21 08:58:06 +02003166 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
willy tarreaue0331262006-05-15 03:02:46 +02003167 "<b>maxsock = </b> %d<br>\n"
3168 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003169 "</td><td width=\"10%%\">\n"
3170 "</td><td align=\"right\">\n"
3171 "<table class=\"lgd\">"
3172 "<tr><td bgcolor=\"#C0FFC0\">&nbsp;</td><td style=\"border-style: none;\">active UP </td>"
3173 "<td bgcolor=\"#B0D0FF\">&nbsp;</td><td style=\"border-style: none;\">backup UP </td></tr>"
3174 "<tr><td bgcolor=\"#FFFFA0\"></td><td style=\"border-style: none;\">active UP, going down </td>"
3175 "<td bgcolor=\"#C060FF\"></td><td style=\"border-style: none;\">backup UP, going down </td></tr>"
3176 "<tr><td bgcolor=\"#FFD020\"></td><td style=\"border-style: none;\">active DOWN, going up </td>"
3177 "<td bgcolor=\"#FF80FF\"></td><td style=\"border-style: none;\">backup DOWN, going up </td></tr>"
3178 "<tr><td bgcolor=\"#FF9090\"></td><td style=\"border-style: none;\">active or backup DOWN &nbsp;</td>"
3179 "<td bgcolor=\"#E0E0E0\"></td><td style=\"border-style: none;\">not checked </td></tr>"
3180 "</table>\n"
3181 "</tr></table>\n"
willy tarreaue0331262006-05-15 03:02:46 +02003182 "",
3183 pid, pid, global.nbproc,
3184 up / 86400, (up % 86400) / 3600,
3185 (up % 3600) / 60, (up % 60),
willy tarreau338be832006-05-21 08:58:06 +02003186 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
3187 global.rlimit_memmax ? " MB" : "",
willy tarreaue0331262006-05-15 03:02:46 +02003188 global.rlimit_nofile,
3189 global.maxsock,
3190 global.maxconn,
3191 actconn
3192 );
willy tarreaucb406512006-05-18 00:52:35 +02003193
3194 if (buffer_write(rep, trash, msglen) != 0)
3195 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003196 msglen = 0;
3197
3198 s->data_state = DATA_ST_DATA;
3199 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
3200
willy tarreaue0331262006-05-15 03:02:46 +02003201 px = s->data_ctx.stats.px = proxy;
willy tarreau1f431b52006-05-21 14:46:15 +02003202 s->data_ctx.stats.px_st = DATA_ST_INIT;
willy tarreaue0331262006-05-15 03:02:46 +02003203 }
3204
3205 while (s->data_ctx.stats.px) {
willy tarreaucb406512006-05-18 00:52:35 +02003206 int dispatch_sess, dispatch_cum;
willy tarreau1f431b52006-05-21 14:46:15 +02003207 int failed_checks, down_trans;
willy tarreaue3b30652006-05-21 16:23:22 +02003208 int failed_secu, failed_conns, failed_resp;
willy tarreaucb406512006-05-18 00:52:35 +02003209
willy tarreau1f431b52006-05-21 14:46:15 +02003210 if (s->data_ctx.stats.px_st == DATA_ST_INIT) {
3211 /* we are on a new proxy */
willy tarreaue0331262006-05-15 03:02:46 +02003212 px = s->data_ctx.stats.px;
willy tarreau1f431b52006-05-21 14:46:15 +02003213
3214 /* skip the disabled proxies */
3215 if (px->state == PR_STSTOPPED)
3216 goto next_proxy;
3217
3218 if (s->proxy->uri_auth && s->proxy->uri_auth->scope) {
3219 /* we have a limited scope, we have to check the proxy name */
3220 struct stat_scope *scope;
3221 int len;
3222
3223 len = strlen(px->id);
3224 scope = s->proxy->uri_auth->scope;
3225
3226 while (scope) {
3227 /* match exact proxy name */
3228 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
3229 break;
3230
3231 /* match '.' which means 'self' proxy */
3232 if (!strcmp(scope->px_id, ".") && px == s->proxy)
3233 break;
3234 scope = scope->next;
3235 }
3236
3237 /* proxy name not found */
3238 if (scope == NULL)
3239 goto next_proxy;
3240 }
3241
3242 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003243 "<h3>&gt; Proxy instance %s : "
3244 "%d conns (maxconn=%d), %d queued (%d unassigned), %d total conns</h3>\n"
3245 "",
3246 px->id,
3247 px->nbconn, px->maxconn, px->totpend, px->nbpend, px->cum_conn);
3248
3249 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue3b30652006-05-21 16:23:22 +02003250 "<table cols=\"16\" class=\"tbl\">\n"
willy tarreaucb406512006-05-18 00:52:35 +02003251 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
3252 "<th colspan=5>Server</th>"
3253 "<th colspan=2>Queue</th>"
3254 "<th colspan=4>Sessions</th>"
willy tarreaue3b30652006-05-21 16:23:22 +02003255 "<th colspan=5>Errors</th></tr>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003256 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
3257 "<th>Name</th><th>Weight</th><th>Status</th><th>Act.</th><th>Bck.</th>"
3258 "<th>Curr.</th><th>Max.</th>"
3259 "<th>Curr.</th><th>Max.</th><th>Limit</th><th>Cumul.</th>"
willy tarreaue3b30652006-05-21 16:23:22 +02003260 "<th>Conn.</th><th>Resp.</th><th>Sec.</th><th>Check</th><th>Down</th></tr>\n");
willy tarreaue0331262006-05-15 03:02:46 +02003261
3262 if (buffer_write(rep, trash, msglen) != 0)
3263 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003264 msglen = 0;
3265
willy tarreaue0331262006-05-15 03:02:46 +02003266 s->data_ctx.stats.sv = px->srv;
willy tarreau1f431b52006-05-21 14:46:15 +02003267 s->data_ctx.stats.px_st = DATA_ST_DATA;
willy tarreaue0331262006-05-15 03:02:46 +02003268 }
3269
willy tarreaucb406512006-05-18 00:52:35 +02003270 px = s->data_ctx.stats.px;
3271
willy tarreau1f431b52006-05-21 14:46:15 +02003272 /* stats.sv has been initialized above */
willy tarreaue0331262006-05-15 03:02:46 +02003273 while (s->data_ctx.stats.sv != NULL) {
willy tarreaucb406512006-05-18 00:52:35 +02003274 static char *act_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FFD020", /*failing*/"#FFFFA0", /*up*/"#C0FFC0", /*unchecked*/"#E0E0E0" };
3275 static char *bck_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FF80ff", /*failing*/"#C060FF", /*up*/"#B0D0FF", /*unchecked*/"#E0E0E0" };
3276 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
3277 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP */
3278
willy tarreaue0331262006-05-15 03:02:46 +02003279 sv = s->data_ctx.stats.sv;
willy tarreaucb406512006-05-18 00:52:35 +02003280
willy tarreaucb406512006-05-18 00:52:35 +02003281 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
3282 if (!(sv->state & SRV_CHECKED))
3283 sv_state = 4;
3284 else if (sv->state & SRV_RUNNING)
3285 if (sv->health == sv->rise + sv->fall - 1)
3286 sv_state = 3; /* UP */
3287 else
3288 sv_state = 2; /* going down */
3289 else
3290 if (sv->health)
3291 sv_state = 1; /* going up */
3292 else
3293 sv_state = 0; /* DOWN */
3294
3295 /* name, weight */
willy tarreau1f431b52006-05-21 14:46:15 +02003296 msglen += snprintf(trash, sizeof(trash),
willy tarreaucb406512006-05-18 00:52:35 +02003297 "<tr align=center bgcolor=\"%s\"><td>%s</td><td>%d</td><td>",
3298 (sv->state & SRV_BACKUP) ? bck_tab_bg[sv_state] : act_tab_bg[sv_state],
3299 sv->id, sv->uweight+1);
3300 /* status */
3301 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, srv_hlt_st[sv_state],
3302 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
3303 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
3304
3305 /* act, bck */
3306 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3307 "</td><td>%s</td><td>%s</td>",
willy tarreaue0331262006-05-15 03:02:46 +02003308 (sv->state & SRV_BACKUP) ? "-" : "Y",
3309 (sv->state & SRV_BACKUP) ? "Y" : "-");
willy tarreaucb406512006-05-18 00:52:35 +02003310
3311 /* queue : current, max */
3312 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3313 "<td align=right>%d</td><td align=right>%d</td>",
3314 sv->nbpend, sv->nbpend_max);
3315
3316 /* sessions : current, max, limit, cumul */
3317 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3318 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>",
3319 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess);
3320
willy tarreaue3b30652006-05-21 16:23:22 +02003321 /* errors : connect, response, security */
3322 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3323 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3324 sv->failed_conns, sv->failed_resp, sv->failed_secu);
3325
3326 /* check failures : unique, fatal */
willy tarreau338be832006-05-21 08:58:06 +02003327 if (sv->state & SRV_CHECKED)
3328 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3329 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3330 sv->failed_checks, sv->down_trans);
3331 else
3332 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3333 "<td align=right>-</td><td align=right>-</td></tr>\n");
willy tarreaucb406512006-05-18 00:52:35 +02003334
willy tarreau1f431b52006-05-21 14:46:15 +02003335 if (buffer_write(rep, trash, msglen) != 0)
3336 return 0;
3337 msglen = 0;
3338
3339 s->data_ctx.stats.sv = sv->next;
3340 } /* while sv */
3341
3342 /* now we are past the last server, we'll dump information about the dispatcher */
3343
3344 /* We have to count down from the proxy to the servers to tell how
3345 * many sessions are on the dispatcher, and how many checks have
3346 * failed. We cannot count this during the servers dump because it
3347 * might be interrupted multiple times.
3348 */
3349 dispatch_sess = px->nbconn;
willy tarreaue3b30652006-05-21 16:23:22 +02003350 dispatch_cum = px->cum_conn;
3351 failed_secu = px->failed_secu;
3352 failed_conns = px->failed_conns;
3353 failed_resp = px->failed_resp;
willy tarreau1f431b52006-05-21 14:46:15 +02003354 failed_checks = down_trans = 0;
3355
3356 sv = px->srv;
3357 while (sv) {
3358 dispatch_sess -= sv->cur_sess;
3359 dispatch_cum -= sv->cum_sess;
willy tarreaue3b30652006-05-21 16:23:22 +02003360 failed_conns -= sv->failed_conns;
3361 failed_resp -= sv->failed_resp;
3362 failed_secu -= sv->failed_secu;
3363 if (sv->state & SRV_CHECKED) {
3364 failed_checks += sv->failed_checks;
3365 down_trans += sv->down_trans;
3366 }
willy tarreaue0331262006-05-15 03:02:46 +02003367 sv = sv->next;
willy tarreau1f431b52006-05-21 14:46:15 +02003368 }
willy tarreaucb406512006-05-18 00:52:35 +02003369
willy tarreau1f431b52006-05-21 14:46:15 +02003370 /* name, weight, status, act, bck */
3371 msglen += snprintf(trash + msglen, sizeof(trash),
3372 "<tr align=center bgcolor=\"#e8e8d0\">"
3373 "<td>Dispatcher</td><td>-</td>"
3374 "<td>%s</td><td>-</td><td>-</td>",
3375 px->state == PR_STRUN ? "UP" : "DOWN");
willy tarreaucb406512006-05-18 00:52:35 +02003376
willy tarreau1f431b52006-05-21 14:46:15 +02003377 /* queue : current, max */
3378 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3379 "<td align=right>%d</td><td align=right>%d</td>",
3380 px->nbpend, px->nbpend_max);
willy tarreaucb406512006-05-18 00:52:35 +02003381
willy tarreau1f431b52006-05-21 14:46:15 +02003382 /* sessions : current, max, limit, cumul. */
3383 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3384 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>",
3385 dispatch_sess, px->nbconn_max, px->maxconn, dispatch_cum);
willy tarreaucb406512006-05-18 00:52:35 +02003386
willy tarreaue3b30652006-05-21 16:23:22 +02003387 /* errors : connect, response, security */
3388 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3389 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3390 failed_conns, failed_resp, failed_secu);
3391
3392 /* check failures : unique, fatal */
willy tarreau1f431b52006-05-21 14:46:15 +02003393 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3394 "<td align=right>-</td><td align=right>-</td></tr>\n");
willy tarreaucb406512006-05-18 00:52:35 +02003395
willy tarreaucb406512006-05-18 00:52:35 +02003396
willy tarreau1f431b52006-05-21 14:46:15 +02003397 /* now the summary for the whole proxy */
3398 /* name, weight, status, act, bck */
3399 msglen += snprintf(trash + msglen, sizeof(trash),
3400 "<tr align=center style=\"color: #ffff80; background: #20C0C0;\">"
3401 "<td><b>Total</b></td><td>-</td>"
3402 "<td><b>%s</b></td><td><b>%d</b></td><td><b>%d</b></td>",
3403 (px->state == PR_STRUN && ((px->srv == NULL) || px->srv_act || px->srv_bck)) ? "UP" : "DOWN",
3404 px->srv_act, px->srv_bck);
willy tarreaucb406512006-05-18 00:52:35 +02003405
willy tarreau1f431b52006-05-21 14:46:15 +02003406 /* queue : current, max */
3407 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3408 "<td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
3409 px->totpend, px->nbpend_max);
willy tarreaucb406512006-05-18 00:52:35 +02003410
willy tarreau1f431b52006-05-21 14:46:15 +02003411 /* sessions : current, max, limit, cumul */
3412 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3413 "<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>",
3414 px->nbconn, px->nbconn_max, px->maxconn, px->cum_conn);
willy tarreaucb406512006-05-18 00:52:35 +02003415
willy tarreaue3b30652006-05-21 16:23:22 +02003416 /* errors : connect, response, security */
3417 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3418 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3419 px->failed_conns, px->failed_resp, px->failed_secu);
3420
3421 /* check failures : unique, fatal */
willy tarreau1f431b52006-05-21 14:46:15 +02003422 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3423 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3424 failed_checks, down_trans);
willy tarreaucb406512006-05-18 00:52:35 +02003425
willy tarreau1f431b52006-05-21 14:46:15 +02003426 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, "</table><p>\n");
3427
3428 if (buffer_write(rep, trash, msglen) != 0)
3429 return 0;
3430 msglen = 0;
3431
3432 s->data_ctx.stats.px_st = DATA_ST_INIT;
3433 next_proxy:
3434 s->data_ctx.stats.px = px->next;
willy tarreaucb406512006-05-18 00:52:35 +02003435 } /* proxy loop */
willy tarreaue0331262006-05-15 03:02:46 +02003436 /* here, we just have reached the sv == NULL and px == NULL */
3437 s->flags &= ~SN_SELF_GEN;
3438 return 1;
3439 }
3440 else {
3441 /* unknown data source */
3442 s->logs.status = 500;
3443 client_retnclose(s, s->proxy->errmsg.len500, s->proxy->errmsg.msg500);
3444 if (!(s->flags & SN_ERR_MASK))
3445 s->flags |= SN_ERR_PRXCOND;
3446 if (!(s->flags & SN_FINST_MASK))
3447 s->flags |= SN_FINST_R;
3448 s->flags &= SN_SELF_GEN;
3449 return 1;
3450 }
3451}
3452
3453
willy tarreau9fe663a2005-12-17 13:02:59 +01003454/*
3455 * send a log for the session when we have enough info about it
3456 */
3457void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003458 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01003459 struct proxy *p = s->proxy;
3460 int log;
3461 char *uri;
3462 char *pxid;
3463 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01003464 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01003465
3466 /* This is a first attempt at a better logging system.
3467 * For now, we rely on send_log() to provide the date, although it obviously
3468 * is the date of the log and not of the request, and most fields are not
3469 * computed.
3470 */
3471
willy tarreaua1598082005-12-17 13:08:06 +01003472 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01003473
willy tarreau8a86dbf2005-12-18 00:45:59 +01003474 if (s->cli_addr.ss_family == AF_INET)
3475 inet_ntop(AF_INET,
3476 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3477 pn, sizeof(pn));
3478 else
3479 inet_ntop(AF_INET6,
3480 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3481 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01003482
willy tarreauc1cae632005-12-17 14:12:23 +01003483 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01003484 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01003485 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01003486
willy tarreauc1cae632005-12-17 14:12:23 +01003487 tm = localtime(&s->logs.tv_accept.tv_sec);
3488 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01003489 char tmpline[MAX_SYSLOG_LEN], *h;
3490 int hdr;
3491
3492 h = tmpline;
3493 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
3494 *(h++) = ' ';
3495 *(h++) = '{';
3496 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
3497 if (hdr)
3498 *(h++) = '|';
3499 if (s->req_cap[hdr] != NULL)
3500 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
3501 }
3502 *(h++) = '}';
3503 }
3504
3505 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
3506 *(h++) = ' ';
3507 *(h++) = '{';
3508 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
3509 if (hdr)
3510 *(h++) = '|';
3511 if (s->rsp_cap[hdr] != NULL)
3512 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
3513 }
3514 *(h++) = '}';
3515 }
3516
3517 if (h < tmpline + sizeof(tmpline) - 4) {
3518 *(h++) = ' ';
3519 *(h++) = '"';
3520 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
3521 *(h++) = '"';
3522 }
3523 *h = '\0';
3524
willy tarreau5e69b162006-05-12 19:49:37 +02003525 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 +01003526 pn,
3527 (s->cli_addr.ss_family == AF_INET) ?
3528 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3529 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01003530 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3531 tm->tm_hour, tm->tm_min, tm->tm_sec,
3532 pxid, srv,
3533 s->logs.t_request,
willy tarreauf32f5242006-05-02 22:54:52 +02003534 (s->logs.t_queue >= 0) ? s->logs.t_queue - s->logs.t_request : -1,
3535 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreaua1598082005-12-17 13:08:06 +01003536 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003537 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3538 s->logs.status,
3539 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01003540 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
3541 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01003542 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
3543 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
3544 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
3545 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau5e69b162006-05-12 19:49:37 +02003546 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3547 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01003548 }
3549 else {
willy tarreau5f15c552006-05-13 18:37:04 +02003550 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 +01003551 pn,
3552 (s->cli_addr.ss_family == AF_INET) ?
3553 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3554 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01003555 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3556 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01003557 pxid, srv,
willy tarreau5f15c552006-05-13 18:37:04 +02003558 (s->logs.t_queue >= 0) ? s->logs.t_queue : -1,
3559 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003560 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3561 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01003562 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01003563 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreau5e69b162006-05-12 19:49:37 +02003564 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3565 s->logs.srv_queue_size, s->logs.prx_queue_size);
willy tarreaua1598082005-12-17 13:08:06 +01003566 }
3567
3568 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003569}
3570
willy tarreaue39cd132005-12-17 13:00:18 +01003571
3572/*
willy tarreau0f7af912005-12-17 12:21:26 +01003573 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01003574 * to an accept. It tries to accept as many connections as possible.
3575 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01003576 */
3577int event_accept(int fd) {
3578 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003579 struct session *s;
3580 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01003581 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01003582 int max_accept;
3583
3584 if (global.nbproc > 1)
3585 max_accept = 8; /* let other processes catch some connections too */
3586 else
3587 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003588
willy tarreauc2becdc2006-03-19 19:36:48 +01003589 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003590 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003591 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01003592
willy tarreaub1285d52005-12-18 01:20:14 +01003593 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
3594 switch (errno) {
3595 case EAGAIN:
3596 case EINTR:
3597 case ECONNABORTED:
3598 return 0; /* nothing more to accept */
3599 case ENFILE:
3600 send_log(p, LOG_EMERG,
3601 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
3602 p->id, maxfd);
3603 return 0;
3604 case EMFILE:
3605 send_log(p, LOG_EMERG,
3606 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
3607 p->id, maxfd);
3608 return 0;
3609 case ENOBUFS:
3610 case ENOMEM:
3611 send_log(p, LOG_EMERG,
3612 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
3613 p->id, maxfd);
3614 return 0;
3615 default:
3616 return 0;
3617 }
3618 }
willy tarreau0f7af912005-12-17 12:21:26 +01003619
willy tarreau5cbea6f2005-12-17 12:48:26 +01003620 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
3621 Alert("out of memory in event_accept().\n");
3622 FD_CLR(fd, StaticReadEvent);
3623 p->state = PR_STIDLE;
3624 close(cfd);
3625 return 0;
3626 }
willy tarreau0f7af912005-12-17 12:21:26 +01003627
willy tarreaub1285d52005-12-18 01:20:14 +01003628 /* if this session comes from a known monitoring system, we want to ignore
3629 * it as soon as possible, which means closing it immediately for TCP.
3630 */
3631 s->flags = 0;
3632 if (addr.ss_family == AF_INET &&
3633 p->mon_mask.s_addr &&
3634 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
3635 if (p->mode == PR_MODE_TCP) {
3636 close(cfd);
3637 pool_free(session, s);
3638 continue;
3639 }
3640 s->flags |= SN_MONITOR;
3641 }
3642
willy tarreau5cbea6f2005-12-17 12:48:26 +01003643 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3644 Alert("out of memory in event_accept().\n");
3645 FD_CLR(fd, StaticReadEvent);
3646 p->state = PR_STIDLE;
3647 close(cfd);
3648 pool_free(session, s);
3649 return 0;
3650 }
willy tarreau0f7af912005-12-17 12:21:26 +01003651
willy tarreau5cbea6f2005-12-17 12:48:26 +01003652 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01003653 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003654 Alert("accept(): not enough free sockets. Raise -n argument. 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 tarreau5cbea6f2005-12-17 12:48:26 +01003661 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
3662 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
3663 (char *) &one, sizeof(one)) == -1)) {
3664 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
3665 close(cfd);
3666 pool_free(task, t);
3667 pool_free(session, s);
3668 return 0;
3669 }
willy tarreau0f7af912005-12-17 12:21:26 +01003670
willy tarreaub952e1d2005-12-18 01:31:20 +01003671 if (p->options & PR_O_TCP_CLI_KA)
3672 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
3673
willy tarreau9fe663a2005-12-17 13:02:59 +01003674 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02003675 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
willy tarreau9fe663a2005-12-17 13:02:59 +01003676 t->state = TASK_IDLE;
3677 t->process = process_session;
3678 t->context = s;
3679
3680 s->task = t;
3681 s->proxy = p;
3682 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
3683 s->srv_state = SV_STIDLE;
3684 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01003685
willy tarreau9fe663a2005-12-17 13:02:59 +01003686 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
3687 s->cli_fd = cfd;
3688 s->srv_fd = -1;
willy tarreau9e138862006-05-14 23:06:28 +02003689 s->req_line.len = -1;
3690 s->auth_hdr.len = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003691 s->srv = NULL;
Willy TARREAU1a71cc12006-05-14 09:10:03 +02003692 s->pend_pos = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01003693 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01003694
willy tarreaub1285d52005-12-18 01:20:14 +01003695 if (s->flags & SN_MONITOR)
3696 s->logs.logwait = 0;
3697 else
3698 s->logs.logwait = p->to_log;
3699
willy tarreaua1598082005-12-17 13:08:06 +01003700 s->logs.tv_accept = now;
3701 s->logs.t_request = -1;
willy tarreauf32f5242006-05-02 22:54:52 +02003702 s->logs.t_queue = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003703 s->logs.t_connect = -1;
3704 s->logs.t_data = -1;
3705 s->logs.t_close = 0;
3706 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01003707 s->logs.cli_cookie = NULL;
3708 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01003709 s->logs.status = -1;
3710 s->logs.bytes = 0;
willy tarreau5e69b162006-05-12 19:49:37 +02003711 s->logs.prx_queue_size = 0; /* we get the number of pending conns before us */
3712 s->logs.srv_queue_size = 0; /* we will get this number soon */
willy tarreau9fe663a2005-12-17 13:02:59 +01003713
willy tarreaue0331262006-05-15 03:02:46 +02003714 s->data_source = DATA_SRC_NONE;
willy tarreaue0331262006-05-15 03:02:46 +02003715
willy tarreau2f6ba652005-12-17 13:57:42 +01003716 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02003717 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01003718
willy tarreau4302f492005-12-18 01:00:37 +01003719 if (p->nb_req_cap > 0) {
3720 if ((s->req_cap =
3721 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
3722 == NULL) { /* no memory */
3723 close(cfd); /* nothing can be done for this fd without memory */
3724 pool_free(task, t);
3725 pool_free(session, s);
3726 return 0;
3727 }
3728 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
3729 }
3730 else
3731 s->req_cap = NULL;
3732
3733 if (p->nb_rsp_cap > 0) {
3734 if ((s->rsp_cap =
3735 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
3736 == NULL) { /* no memory */
3737 if (s->req_cap != NULL)
3738 pool_free_to(p->req_cap_pool, s->req_cap);
3739 close(cfd); /* nothing can be done for this fd without memory */
3740 pool_free(task, t);
3741 pool_free(session, s);
3742 return 0;
3743 }
3744 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
3745 }
3746 else
3747 s->rsp_cap = NULL;
3748
willy tarreau5cbea6f2005-12-17 12:48:26 +01003749 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
3750 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003751 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003752 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01003753
willy tarreau8a86dbf2005-12-18 00:45:59 +01003754 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003755 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003756 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003757 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01003758
willy tarreau9fe663a2005-12-17 13:02:59 +01003759 if (p->to_log) {
3760 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01003761 if (s->logs.logwait & LW_CLIP)
3762 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01003763 sess_log(s);
3764 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01003765 else if (s->cli_addr.ss_family == AF_INET) {
3766 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
3767 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
3768 sn, sizeof(sn)) &&
3769 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3770 pn, sizeof(pn))) {
3771 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3772 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
3773 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
3774 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3775 }
3776 }
3777 else {
3778 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
3779 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
3780 sn, sizeof(sn)) &&
3781 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
3782 pn, sizeof(pn))) {
3783 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3784 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
3785 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
3786 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3787 }
3788 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003789 }
willy tarreau0f7af912005-12-17 12:21:26 +01003790
willy tarreau982249e2005-12-18 00:57:06 +01003791 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01003792 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003793 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01003794 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01003795 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003796 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003797 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01003798 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01003799
willy tarreau8a86dbf2005-12-18 00:45:59 +01003800 if (s->cli_addr.ss_family == AF_INET) {
3801 char pn[INET_ADDRSTRLEN];
3802 inet_ntop(AF_INET,
3803 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_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_in *)&s->cli_addr)->sin_port));
3809 }
3810 else {
3811 char pn[INET6_ADDRSTRLEN];
3812 inet_ntop(AF_INET6,
3813 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3814 pn, sizeof(pn));
3815
3816 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3817 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3818 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3819 }
3820
willy tarreauef900ab2005-12-17 12:52:52 +01003821 write(1, trash, len);
3822 }
willy tarreau0f7af912005-12-17 12:21:26 +01003823
willy tarreau5cbea6f2005-12-17 12:48:26 +01003824 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003825 if (s->rsp_cap != NULL)
3826 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3827 if (s->req_cap != NULL)
3828 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003829 close(cfd); /* nothing can be done for this fd without memory */
3830 pool_free(task, t);
3831 pool_free(session, s);
3832 return 0;
3833 }
willy tarreau4302f492005-12-18 01:00:37 +01003834
willy tarreau5cbea6f2005-12-17 12:48:26 +01003835 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003836 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003837 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3838 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003839 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003840 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003841
willy tarreau5cbea6f2005-12-17 12:48:26 +01003842 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3843 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003844 if (s->rsp_cap != NULL)
3845 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3846 if (s->req_cap != NULL)
3847 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003848 close(cfd); /* nothing can be done for this fd without memory */
3849 pool_free(task, t);
3850 pool_free(session, s);
3851 return 0;
3852 }
3853 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003854 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003855 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 +01003856
willy tarreau5cbea6f2005-12-17 12:48:26 +01003857 fdtab[cfd].read = &event_cli_read;
3858 fdtab[cfd].write = &event_cli_write;
3859 fdtab[cfd].owner = t;
3860 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003861
willy tarreaub1285d52005-12-18 01:20:14 +01003862 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3863 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3864 /* Either we got a request from a monitoring system on an HTTP instance,
3865 * or we're in health check mode with the 'httpchk' option enabled. In
3866 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3867 */
3868 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3869 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3870 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003871 }
3872 else {
3873 FD_SET(cfd, StaticReadEvent);
3874 }
3875
willy tarreaub952e1d2005-12-18 01:31:20 +01003876#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3877 if (PrevReadEvent) {
3878 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3879 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3880 }
3881#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003882 fd_insert(cfd);
3883
3884 tv_eternity(&s->cnexpire);
3885 tv_eternity(&s->srexpire);
3886 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003887 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003888 tv_eternity(&s->cwexpire);
3889
willy tarreaub1285d52005-12-18 01:20:14 +01003890 if (s->proxy->clitimeout) {
3891 if (FD_ISSET(cfd, StaticReadEvent))
3892 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3893 if (FD_ISSET(cfd, StaticWriteEvent))
3894 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3895 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003896
willy tarreaub1285d52005-12-18 01:20:14 +01003897 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003898
3899 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003900
3901 if (p->mode != PR_MODE_HEALTH)
3902 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003903
3904 p->nbconn++;
willy tarreaucb406512006-05-18 00:52:35 +02003905 if (p->nbconn > p->nbconn_max)
3906 p->nbconn_max = p->nbconn;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003907 actconn++;
3908 totalconn++;
3909
willy tarreaub952e1d2005-12-18 01:31:20 +01003910 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003911 } /* end of while (p->nbconn < p->maxconn) */
3912 return 0;
3913}
willy tarreau0f7af912005-12-17 12:21:26 +01003914
willy tarreau0f7af912005-12-17 12:21:26 +01003915
willy tarreau5cbea6f2005-12-17 12:48:26 +01003916/*
3917 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003918 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3919 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003920 * or -1 if an error occured.
3921 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003922int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003923 struct task *t = fdtab[fd].owner;
3924 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003925 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003926 socklen_t lskerr = sizeof(skerr);
3927
willy tarreau05be12b2006-03-19 19:35:00 +01003928 skerr = 1;
3929 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3930 || (skerr != 0)) {
3931 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003932 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003933 fdtab[fd].state = FD_STERROR;
3934 FD_CLR(fd, StaticWriteEvent);
3935 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003936 else if (s->result != -1) {
3937 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003938 if (s->proxy->options & PR_O_HTTP_CHK) {
3939 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003940 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003941 * so we'll send the request, and won't wake the checker up now.
3942 */
3943#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003944 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003945#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003946 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003947#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003948 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003949 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3950 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3951 return 0;
3952 }
willy tarreau05be12b2006-03-19 19:35:00 +01003953 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003954 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003955 FD_CLR(fd, StaticWriteEvent);
3956 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003957 }
3958 else {
3959 /* good TCP connection is enough */
3960 s->result = 1;
3961 }
3962 }
3963
3964 task_wakeup(&rq, t);
3965 return 0;
3966}
3967
willy tarreau0f7af912005-12-17 12:21:26 +01003968
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003969/*
3970 * This function is used only for server health-checks. It handles
3971 * the server's reply to an HTTP request. It returns 1 if the server replies
3972 * 2xx or 3xx (valid responses), or -1 in other cases.
3973 */
3974int event_srv_chk_r(int fd) {
3975 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003976 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003977 struct task *t = fdtab[fd].owner;
3978 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003979 int skerr;
3980 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003981
willy tarreaua4a583a2005-12-18 01:39:19 +01003982 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003983
willy tarreau05be12b2006-03-19 19:35:00 +01003984 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3985 if (!skerr) {
3986#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003987 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003988#else
willy tarreau05be12b2006-03-19 19:35:00 +01003989 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3990 * but the connection was closed on the remote end. Fortunately, recv still
3991 * works correctly and we don't need to do the getsockopt() on linux.
3992 */
3993 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003994#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003995
3996 if ((len >= sizeof("HTTP/1.0 000")) &&
3997 !memcmp(reply, "HTTP/1.", 7) &&
3998 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3999 result = 1;
4000 }
4001
4002 if (result == -1)
4003 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01004004
4005 if (s->result != -1)
4006 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004007
4008 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004009 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01004010 return 0;
4011}
4012
4013
4014/*
4015 * this function writes the string <str> at position <pos> which must be in buffer <b>,
4016 * and moves <end> just after the end of <str>.
4017 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
4018 * the shift value (positive or negative) is returned.
4019 * If there's no space left, the move is not done.
4020 *
4021 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004022int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01004023 int delta;
4024 int len;
4025
4026 len = strlen(str);
4027 delta = len - (end - pos);
4028
4029 if (delta + b->r >= b->data + BUFSIZE)
4030 return 0; /* no space left */
4031
4032 /* first, protect the end of the buffer */
4033 memmove(end + delta, end, b->data + b->l - end);
4034
4035 /* now, copy str over pos */
4036 memcpy(pos, str,len);
4037
willy tarreau5cbea6f2005-12-17 12:48:26 +01004038 /* we only move data after the displaced zone */
4039 if (b->r > pos) b->r += delta;
4040 if (b->w > pos) b->w += delta;
4041 if (b->h > pos) b->h += delta;
4042 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01004043 b->l += delta;
4044
4045 return delta;
4046}
4047
willy tarreau8337c6b2005-12-17 13:41:01 +01004048/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01004049 * len is 0.
4050 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004051int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01004052 int delta;
4053
4054 delta = len - (end - pos);
4055
4056 if (delta + b->r >= b->data + BUFSIZE)
4057 return 0; /* no space left */
4058
Willy TARREAUe78ae262006-01-08 01:24:12 +01004059 if (b->data + b->l < end)
4060 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
4061 return 0;
4062
willy tarreau0f7af912005-12-17 12:21:26 +01004063 /* first, protect the end of the buffer */
4064 memmove(end + delta, end, b->data + b->l - end);
4065
4066 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01004067 if (len)
4068 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01004069
willy tarreau5cbea6f2005-12-17 12:48:26 +01004070 /* we only move data after the displaced zone */
4071 if (b->r > pos) b->r += delta;
4072 if (b->w > pos) b->w += delta;
4073 if (b->h > pos) b->h += delta;
4074 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01004075 b->l += delta;
4076
4077 return delta;
4078}
4079
4080
4081int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
4082 char *old_dst = dst;
4083
4084 while (*str) {
4085 if (*str == '\\') {
4086 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01004087 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004088 int len, num;
4089
4090 num = *str - '0';
4091 str++;
4092
willy tarreau8a86dbf2005-12-18 00:45:59 +01004093 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01004094 len = matches[num].rm_eo - matches[num].rm_so;
4095 memcpy(dst, src + matches[num].rm_so, len);
4096 dst += len;
4097 }
4098
4099 }
4100 else if (*str == 'x') {
4101 unsigned char hex1, hex2;
4102 str++;
4103
willy tarreauc1f47532005-12-18 01:08:26 +01004104 hex1 = toupper(*str++) - '0';
4105 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01004106
4107 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
4108 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
4109 *dst++ = (hex1<<4) + hex2;
4110 }
4111 else
4112 *dst++ = *str++;
4113 }
4114 else
4115 *dst++ = *str++;
4116 }
4117 *dst = 0;
4118 return dst - old_dst;
4119}
4120
willy tarreauc1f47532005-12-18 01:08:26 +01004121static int ishex(char s)
4122{
4123 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
4124}
4125
4126/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
4127char *check_replace_string(char *str)
4128{
4129 char *err = NULL;
4130 while (*str) {
4131 if (*str == '\\') {
4132 err = str; /* in case of a backslash, we return the pointer to it */
4133 str++;
4134 if (!*str)
4135 return err;
4136 else if (isdigit((int)*str))
4137 err = NULL;
4138 else if (*str == 'x') {
4139 str++;
4140 if (!ishex(*str))
4141 return err;
4142 str++;
4143 if (!ishex(*str))
4144 return err;
4145 err = NULL;
4146 }
4147 else {
4148 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
4149 err = NULL;
4150 }
4151 }
4152 str++;
4153 }
4154 return err;
4155}
4156
willy tarreau0f7af912005-12-17 12:21:26 +01004157/*
4158 * manages the client FSM and its socket. BTW, it also tries to handle the
4159 * cookie. It returns 1 if a state has changed (and a resync may be needed),
4160 * 0 else.
4161 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004162int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004163 int s = t->srv_state;
4164 int c = t->cli_state;
4165 struct buffer *req = t->req;
4166 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004167 int method_checked = 0;
4168 appsess *asession_temp = NULL;
4169 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01004170
willy tarreau750a4722005-12-17 13:21:24 +01004171#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01004172 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
4173 cli_stnames[c], srv_stnames[s],
4174 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4175 t->crexpire.tv_sec, t->crexpire.tv_usec,
4176 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01004177#endif
willy tarreau0f7af912005-12-17 12:21:26 +01004178 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4179 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4180 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4181 //);
4182 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004183 /* now parse the partial (or complete) headers */
4184 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
4185 char *ptr;
4186 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01004187 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01004188
willy tarreau5cbea6f2005-12-17 12:48:26 +01004189 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01004190
willy tarreau0f7af912005-12-17 12:21:26 +01004191 /* look for the end of the current header */
4192 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
4193 ptr++;
4194
willy tarreau5cbea6f2005-12-17 12:48:26 +01004195 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004196 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02004197
4198 /*
4199 * first, let's check that it's not a leading empty line, in
4200 * which case we'll ignore and remove it (according to RFC2616).
4201 */
4202 if (req->h == req->data) {
4203 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4204 if (ptr > req->r - 2) {
4205 /* this is a partial header, let's wait for more to come */
4206 req->lr = ptr;
4207 break;
4208 }
4209
4210 /* now we know that *ptr is either \r or \n,
4211 * and that there are at least 1 char after it.
4212 */
4213 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4214 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4215 else
4216 req->lr = ptr + 2; /* \r\n or \n\r */
4217 /* ignore empty leading lines */
4218 buffer_replace2(req, req->h, req->lr, NULL, 0);
4219 req->h = req->lr;
4220 continue;
4221 }
4222
willy tarreau5cbea6f2005-12-17 12:48:26 +01004223 /* we can only get here after an end of headers */
4224 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01004225
willy tarreaue39cd132005-12-17 13:00:18 +01004226 if (t->flags & SN_CLDENY) {
4227 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01004228 t->logs.status = 403;
willy tarreau47ee7ad2006-05-18 01:25:36 +02004229 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now); /* let's log the request time */
willy tarreau8337c6b2005-12-17 13:41:01 +01004230 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01004231 if (!(t->flags & SN_ERR_MASK))
4232 t->flags |= SN_ERR_PRXCOND;
4233 if (!(t->flags & SN_FINST_MASK))
4234 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004235 return 1;
4236 }
4237
willy tarreau9e138862006-05-14 23:06:28 +02004238 /* Right now, we know that we have processed the entire headers
4239 * and that unwanted requests have been filtered out. We can do
4240 * whatever we want.
4241 */
4242
willy tarreau9e138862006-05-14 23:06:28 +02004243 if (t->proxy->uri_auth != NULL
4244 && t->req_line.len >= t->proxy->uri_auth->uri_len + 4) { /* +4 for "GET /" */
4245 if (!memcmp(t->req_line.str + 4,
4246 t->proxy->uri_auth->uri_prefix, t->proxy->uri_auth->uri_len)
4247 && !memcmp(t->req_line.str, "GET ", 4)) {
4248 struct user_auth *user;
4249 int authenticated;
4250
4251 /* we are in front of a interceptable URI. Let's check
4252 * if there's an authentication and if it's valid.
4253 */
4254 user = t->proxy->uri_auth->users;
4255 if (!user) {
4256 /* no user auth required, it's OK */
4257 authenticated = 1;
4258 } else {
4259 authenticated = 0;
4260
4261 /* a user list is defined, we have to check.
4262 * skip 21 chars for "Authorization: Basic ".
4263 */
4264 if (t->auth_hdr.len < 21 || memcmp(t->auth_hdr.str + 14, " Basic ", 7))
4265 user = NULL;
4266
4267 while (user) {
4268 if ((t->auth_hdr.len == user->user_len + 21)
4269 && !memcmp(t->auth_hdr.str+21, user->user_pwd, user->user_len)) {
4270 authenticated = 1;
4271 break;
4272 }
4273 user = user->next;
willy tarreau9e138862006-05-14 23:06:28 +02004274 }
4275 }
4276
4277 if (!authenticated) {
4278 int msglen;
4279
4280 /* no need to go further */
4281
4282 msglen = sprintf(trash, HTTP_401_fmt, t->proxy->uri_auth->auth_realm);
4283 t->logs.status = 401;
4284 client_retnclose(t, msglen, trash);
4285 if (!(t->flags & SN_ERR_MASK))
4286 t->flags |= SN_ERR_PRXCOND;
4287 if (!(t->flags & SN_FINST_MASK))
4288 t->flags |= SN_FINST_R;
4289 return 1;
4290 }
4291
willy tarreaue0331262006-05-15 03:02:46 +02004292 t->cli_state = CL_STSHUTR;
willy tarreau950609c2006-05-18 01:23:51 +02004293 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
4294 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreaue0331262006-05-15 03:02:46 +02004295 t->data_source = DATA_SRC_STATS;
willy tarreau1f431b52006-05-21 14:46:15 +02004296 t->data_state = DATA_ST_INIT;
willy tarreaue0331262006-05-15 03:02:46 +02004297 produce_content(t);
4298 return 1;
willy tarreau9e138862006-05-14 23:06:28 +02004299 }
4300 }
4301
4302
willy tarreau5cbea6f2005-12-17 12:48:26 +01004303 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004304 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
4305 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004306 }
willy tarreau0f7af912005-12-17 12:21:26 +01004307
willy tarreau9fe663a2005-12-17 13:02:59 +01004308 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01004309 if (t->cli_addr.ss_family == AF_INET) {
4310 unsigned char *pn;
4311 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
4312 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
4313 pn[0], pn[1], pn[2], pn[3]);
4314 buffer_replace2(req, req->h, req->h, trash, len);
4315 }
4316 else if (t->cli_addr.ss_family == AF_INET6) {
4317 char pn[INET6_ADDRSTRLEN];
4318 inet_ntop(AF_INET6,
4319 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
4320 pn, sizeof(pn));
4321 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
4322 buffer_replace2(req, req->h, req->h, trash, len);
4323 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004324 }
4325
willy tarreau25c4ea52005-12-18 00:49:49 +01004326 /* add a "connection: close" line if needed */
4327 if (t->proxy->options & PR_O_HTTP_CLOSE)
4328 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
4329
willy tarreau982249e2005-12-18 00:57:06 +01004330 if (!memcmp(req->data, "POST ", 5)) {
4331 /* this is a POST request, which is not cacheable by default */
4332 t->flags |= SN_POST;
4333 }
willy tarreaucd878942005-12-17 13:27:43 +01004334
willy tarreau5cbea6f2005-12-17 12:48:26 +01004335 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004336 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01004337
willy tarreau750a4722005-12-17 13:21:24 +01004338 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004339 /* FIXME: we'll set the client in a wait state while we try to
4340 * connect to the server. Is this really needed ? wouldn't it be
willy tarreau0889c962006-04-24 14:36:48 +02004341 * better to release the maximum of system buffers instead ?
4342 * The solution is to enable the FD but set its time-out to
4343 * eternity as long as the server-side does not enable data xfer.
4344 * CL_STDATA also has to take care of this, which is done below.
4345 */
willy tarreauef900ab2005-12-17 12:52:52 +01004346 //FD_CLR(t->cli_fd, StaticReadEvent);
4347 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01004348
4349 /* FIXME: if we break here (as up to 1.1.23), having the client
4350 * shutdown its connection can lead to an abort further.
4351 * it's better to either return 1 or even jump directly to the
4352 * data state which will save one schedule.
4353 */
4354 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01004355
4356 if (!t->proxy->clitimeout ||
4357 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4358 /* If the client has no timeout, or if the server is not ready yet,
4359 * and we know for sure that it can expire, then it's cleaner to
4360 * disable the timeout on the client side so that too low values
4361 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01004362 *
4363 * FIXME-20050705: the server needs a way to re-enable this time-out
4364 * when it switches its state, otherwise a client can stay connected
4365 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01004366 */
4367 tv_eternity(&t->crexpire);
4368
willy tarreau197e8ec2005-12-17 14:10:59 +01004369 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004370 }
willy tarreau0f7af912005-12-17 12:21:26 +01004371
Willy TARREAU13032e72006-03-12 17:31:45 +01004372 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4373 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004374 /* this is a partial header, let's wait for more to come */
4375 req->lr = ptr;
4376 break;
4377 }
willy tarreau0f7af912005-12-17 12:21:26 +01004378
willy tarreau5cbea6f2005-12-17 12:48:26 +01004379 /* now we know that *ptr is either \r or \n,
4380 * and that there are at least 1 char after it.
4381 */
4382 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4383 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4384 else
4385 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01004386
willy tarreau5cbea6f2005-12-17 12:48:26 +01004387 /*
4388 * now we know that we have a full header ; we can do whatever
4389 * we want with these pointers :
4390 * req->h = beginning of header
4391 * ptr = end of header (first \r or \n)
4392 * req->lr = beginning of next line (next rep->h)
4393 * req->r = end of data (not used at this stage)
4394 */
willy tarreau0f7af912005-12-17 12:21:26 +01004395
willy tarreau12350152005-12-18 01:03:27 +01004396 if (!method_checked && (t->proxy->appsession_name != NULL) &&
4397 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
4398 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
4399
4400 /* skip ; */
4401 request_line++;
4402
4403 /* look if we have a jsessionid */
4404
4405 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
4406
4407 /* skip jsessionid= */
4408 request_line += t->proxy->appsession_name_len + 1;
4409
4410 /* First try if we allready have an appsession */
4411 asession_temp = &local_asession;
4412
4413 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4414 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
4415 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
4416 return 0;
4417 }
4418
4419 /* Copy the sessionid */
4420 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
4421 asession_temp->sessid[t->proxy->appsession_len] = 0;
4422 asession_temp->serverid = NULL;
4423
4424 /* only do insert, if lookup fails */
4425 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
4426 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4427 Alert("Not enough memory process_cli():asession:calloc().\n");
4428 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4429 return 0;
4430 }
4431 asession_temp->sessid = local_asession.sessid;
4432 asession_temp->serverid = local_asession.serverid;
4433 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004434 } /* end if (chtbl_lookup()) */
4435 else {
willy tarreau12350152005-12-18 01:03:27 +01004436 /*free wasted memory;*/
4437 pool_free_to(apools.sessid, local_asession.sessid);
4438 }
4439
4440 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4441 asession_temp->request_count++;
4442
4443#if defined(DEBUG_HASH)
4444 print_table(&(t->proxy->htbl_proxy));
4445#endif
4446
4447 if (asession_temp->serverid == NULL) {
4448 Alert("Found Application Session without matching server.\n");
4449 } else {
4450 struct server *srv = t->proxy->srv;
4451 while (srv) {
4452 if (strcmp(srv->id, asession_temp->serverid) == 0) {
4453 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4454 /* we found the server and it's usable */
4455 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004456 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004457 t->srv = srv;
4458 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01004459 } else {
willy tarreau12350152005-12-18 01:03:27 +01004460 t->flags &= ~SN_CK_MASK;
4461 t->flags |= SN_CK_DOWN;
4462 }
willy tarreaub952e1d2005-12-18 01:31:20 +01004463 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01004464 srv = srv->next;
4465 }/* end while(srv) */
4466 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01004467 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01004468 else {
4469 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
4470 }
willy tarreau598da412005-12-18 01:07:29 +01004471 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01004472 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01004473 else{
4474 //printf("No Methode-Header with Session-String\n");
4475 }
4476
willy tarreau8337c6b2005-12-17 13:41:01 +01004477 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004478 /* we have a complete HTTP request that we must log */
4479 int urilen;
4480
willy tarreaua1598082005-12-17 13:08:06 +01004481 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004482 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01004483 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01004484 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01004485 if (!(t->flags & SN_ERR_MASK))
4486 t->flags |= SN_ERR_PRXCOND;
4487 if (!(t->flags & SN_FINST_MASK))
4488 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01004489 return 1;
4490 }
4491
4492 urilen = ptr - req->h;
4493 if (urilen >= REQURI_LEN)
4494 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01004495 memcpy(t->logs.uri, req->h, urilen);
4496 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004497
willy tarreaua1598082005-12-17 13:08:06 +01004498 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01004499 sess_log(t);
4500 }
willy tarreau4302f492005-12-18 01:00:37 +01004501 else if (t->logs.logwait & LW_REQHDR) {
4502 struct cap_hdr *h;
4503 int len;
4504 for (h = t->proxy->req_cap; h; h = h->next) {
4505 if ((h->namelen + 2 <= ptr - req->h) &&
4506 (req->h[h->namelen] == ':') &&
4507 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
4508
4509 if (t->req_cap[h->index] == NULL)
4510 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4511
4512 len = ptr - (req->h + h->namelen + 2);
4513 if (len > h->len)
4514 len = h->len;
4515
4516 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
4517 t->req_cap[h->index][len]=0;
4518 }
4519 }
4520
4521 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004522
willy tarreau5cbea6f2005-12-17 12:48:26 +01004523 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004524
willy tarreau982249e2005-12-18 00:57:06 +01004525 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004526 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004527 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 +01004528 max = ptr - req->h;
4529 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004530 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004531 trash[len++] = '\n';
4532 write(1, trash, len);
4533 }
willy tarreau0f7af912005-12-17 12:21:26 +01004534
willy tarreau25c4ea52005-12-18 00:49:49 +01004535
4536 /* remove "connection: " if needed */
4537 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4538 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
4539 delete_header = 1;
4540 }
4541
willy tarreau5cbea6f2005-12-17 12:48:26 +01004542 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004543 if (!delete_header && t->proxy->req_exp != NULL
4544 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004545 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004546 char term;
4547
4548 term = *ptr;
4549 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004550 exp = t->proxy->req_exp;
4551 do {
4552 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
4553 switch (exp->action) {
4554 case ACT_ALLOW:
4555 if (!(t->flags & SN_CLDENY))
4556 t->flags |= SN_CLALLOW;
4557 break;
4558 case ACT_REPLACE:
4559 if (!(t->flags & SN_CLDENY)) {
4560 int len = exp_replace(trash, req->h, exp->replace, pmatch);
4561 ptr += buffer_replace2(req, req->h, ptr, trash, len);
4562 }
4563 break;
4564 case ACT_REMOVE:
4565 if (!(t->flags & SN_CLDENY))
4566 delete_header = 1;
4567 break;
4568 case ACT_DENY:
4569 if (!(t->flags & SN_CLALLOW))
4570 t->flags |= SN_CLDENY;
4571 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004572 case ACT_PASS: /* we simply don't deny this one */
4573 break;
willy tarreau0f7af912005-12-17 12:21:26 +01004574 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004575 break;
willy tarreau0f7af912005-12-17 12:21:26 +01004576 }
willy tarreaue39cd132005-12-17 13:00:18 +01004577 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004578 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01004579 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004580
willy tarreau240afa62005-12-17 13:14:35 +01004581 /* Now look for cookies. Conforming to RFC2109, we have to support
4582 * attributes whose name begin with a '$', and associate them with
4583 * the right cookie, if we want to delete this cookie.
4584 * So there are 3 cases for each cookie read :
4585 * 1) it's a special attribute, beginning with a '$' : ignore it.
4586 * 2) it's a server id cookie that we *MAY* want to delete : save
4587 * some pointers on it (last semi-colon, beginning of cookie...)
4588 * 3) it's an application cookie : we *MAY* have to delete a previous
4589 * "special" cookie.
4590 * At the end of loop, if a "special" cookie remains, we may have to
4591 * remove it. If no application cookie persists in the header, we
4592 * *MUST* delete it
4593 */
willy tarreau12350152005-12-18 01:03:27 +01004594 if (!delete_header &&
4595 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01004596 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01004597 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004598 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01004599 char *del_colon, *del_cookie, *colon;
4600 int app_cookies;
4601
willy tarreau5cbea6f2005-12-17 12:48:26 +01004602 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01004603 colon = p1;
4604 /* del_cookie == NULL => nothing to be deleted */
4605 del_colon = del_cookie = NULL;
4606 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004607
4608 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01004609 /* skip spaces and colons, but keep an eye on these ones */
4610 while (p1 < ptr) {
4611 if (*p1 == ';' || *p1 == ',')
4612 colon = p1;
4613 else if (!isspace((int)*p1))
4614 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004615 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01004616 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004617
4618 if (p1 == ptr)
4619 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004620
4621 /* p1 is at the beginning of the cookie name */
4622 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01004623 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004624 p2++;
4625
4626 if (p2 == ptr)
4627 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004628
4629 p3 = p2 + 1; /* skips the '=' sign */
4630 if (p3 == ptr)
4631 break;
4632
willy tarreau240afa62005-12-17 13:14:35 +01004633 p4 = p3;
4634 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004635 p4++;
4636
4637 /* here, we have the cookie name between p1 and p2,
4638 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01004639 * we can process it :
4640 *
4641 * Cookie: NAME=VALUE;
4642 * | || || |
4643 * | || || +--> p4
4644 * | || |+-------> p3
4645 * | || +--------> p2
4646 * | |+------------> p1
4647 * | +-------------> colon
4648 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01004649 */
4650
willy tarreau240afa62005-12-17 13:14:35 +01004651 if (*p1 == '$') {
4652 /* skip this one */
4653 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004654 else {
4655 /* first, let's see if we want to capture it */
4656 if (t->proxy->capture_name != NULL &&
4657 t->logs.cli_cookie == NULL &&
4658 (p4 - p1 >= t->proxy->capture_namelen) &&
4659 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4660 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004661
willy tarreau8337c6b2005-12-17 13:41:01 +01004662 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4663 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01004664 } else {
4665 if (log_len > t->proxy->capture_len)
4666 log_len = t->proxy->capture_len;
4667 memcpy(t->logs.cli_cookie, p1, log_len);
4668 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01004669 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004670 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004671
4672 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4673 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
4674 /* Cool... it's the right one */
4675 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01004676 char *delim;
4677
4678 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4679 * have the server ID betweek p3 and delim, and the original cookie between
4680 * delim+1 and p4. Otherwise, delim==p4 :
4681 *
4682 * Cookie: NAME=SRV~VALUE;
4683 * | || || | |
4684 * | || || | +--> p4
4685 * | || || +--------> delim
4686 * | || |+-----------> p3
4687 * | || +------------> p2
4688 * | |+----------------> p1
4689 * | +-----------------> colon
4690 * +------------------------> req->h
4691 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004692
willy tarreau0174f312005-12-18 01:02:42 +01004693 if (t->proxy->options & PR_O_COOK_PFX) {
4694 for (delim = p3; delim < p4; delim++)
4695 if (*delim == COOKIE_DELIM)
4696 break;
4697 }
4698 else
4699 delim = p4;
4700
4701
4702 /* Here, we'll look for the first running server which supports the cookie.
4703 * This allows to share a same cookie between several servers, for example
4704 * to dedicate backup servers to specific servers only.
willy tarreau422bb2e2006-05-10 04:27:21 +02004705 * However, to prevent clients from sticking to cookie-less backup server
4706 * when they have incidentely learned an empty cookie, we simply ignore
4707 * empty cookies and mark them as invalid.
willy tarreau0174f312005-12-18 01:02:42 +01004708 */
willy tarreau422bb2e2006-05-10 04:27:21 +02004709 if (delim == p3)
4710 srv = NULL;
4711
willy tarreau0174f312005-12-18 01:02:42 +01004712 while (srv) {
4713 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
4714 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4715 /* we found the server and it's usable */
4716 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004717 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau0174f312005-12-18 01:02:42 +01004718 t->srv = srv;
4719 break;
willy tarreau12350152005-12-18 01:03:27 +01004720 } else {
willy tarreau0174f312005-12-18 01:02:42 +01004721 /* we found a server, but it's down */
4722 t->flags &= ~SN_CK_MASK;
4723 t->flags |= SN_CK_DOWN;
4724 }
4725 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004726 srv = srv->next;
4727 }
4728
willy tarreau0174f312005-12-18 01:02:42 +01004729 if (!srv && !(t->flags & SN_CK_DOWN)) {
4730 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01004731 t->flags &= ~SN_CK_MASK;
4732 t->flags |= SN_CK_INVALID;
4733 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004734
willy tarreau0174f312005-12-18 01:02:42 +01004735 /* depending on the cookie mode, we may have to either :
4736 * - delete the complete cookie if we're in insert+indirect mode, so that
4737 * the server never sees it ;
4738 * - remove the server id from the cookie value, and tag the cookie as an
4739 * application cookie so that it does not get accidentely removed later,
4740 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01004741 */
willy tarreau0174f312005-12-18 01:02:42 +01004742 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
4743 buffer_replace2(req, p3, delim + 1, NULL, 0);
4744 p4 -= (delim + 1 - p3);
4745 ptr -= (delim + 1 - p3);
4746 del_cookie = del_colon = NULL;
4747 app_cookies++; /* protect the header from deletion */
4748 }
4749 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01004750 (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 +01004751 del_cookie = p1;
4752 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01004753 }
willy tarreau12350152005-12-18 01:03:27 +01004754 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01004755 /* now we know that we must keep this cookie since it's
4756 * not ours. But if we wanted to delete our cookie
4757 * earlier, we cannot remove the complete header, but we
4758 * can remove the previous block itself.
4759 */
4760 app_cookies++;
4761
4762 if (del_cookie != NULL) {
4763 buffer_replace2(req, del_cookie, p1, NULL, 0);
4764 p4 -= (p1 - del_cookie);
4765 ptr -= (p1 - del_cookie);
4766 del_cookie = del_colon = NULL;
4767 }
willy tarreau240afa62005-12-17 13:14:35 +01004768 }
willy tarreau12350152005-12-18 01:03:27 +01004769
4770 if ((t->proxy->appsession_name != NULL) &&
4771 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4772 /* first, let's see if the cookie is our appcookie*/
4773
4774 /* Cool... it's the right one */
4775
4776 asession_temp = &local_asession;
4777
4778 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4779 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4780 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4781 return 0;
4782 }
4783
4784 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4785 asession_temp->sessid[t->proxy->appsession_len] = 0;
4786 asession_temp->serverid = NULL;
4787
4788 /* only do insert, if lookup fails */
4789 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4790 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4791 Alert("Not enough memory process_cli():asession:calloc().\n");
4792 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4793 return 0;
4794 }
4795
4796 asession_temp->sessid = local_asession.sessid;
4797 asession_temp->serverid = local_asession.serverid;
4798 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4799 }
4800 else{
4801 /* free wasted memory */
4802 pool_free_to(apools.sessid, local_asession.sessid);
4803 }
4804
4805 if (asession_temp->serverid == NULL) {
4806 Alert("Found Application Session without matching server.\n");
4807 } else {
4808 struct server *srv = t->proxy->srv;
4809 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01004810 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01004811 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4812 /* we found the server and it's usable */
4813 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004814 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004815 t->srv = srv;
4816 break;
4817 } else {
4818 t->flags &= ~SN_CK_MASK;
4819 t->flags |= SN_CK_DOWN;
4820 }
4821 }
4822 srv = srv->next;
4823 }/* end while(srv) */
4824 }/* end else if server == NULL */
4825
4826 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01004827 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004828 }
willy tarreau240afa62005-12-17 13:14:35 +01004829
willy tarreau5cbea6f2005-12-17 12:48:26 +01004830 /* we'll have to look for another cookie ... */
4831 p1 = p4;
4832 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01004833
4834 /* There's no more cookie on this line.
4835 * We may have marked the last one(s) for deletion.
4836 * We must do this now in two ways :
4837 * - if there is no app cookie, we simply delete the header ;
4838 * - if there are app cookies, we must delete the end of the
4839 * string properly, including the colon/semi-colon before
4840 * the cookie name.
4841 */
4842 if (del_cookie != NULL) {
4843 if (app_cookies) {
4844 buffer_replace2(req, del_colon, ptr, NULL, 0);
4845 /* WARNING! <ptr> becomes invalid for now. If some code
4846 * below needs to rely on it before the end of the global
4847 * header loop, we need to correct it with this code :
willy tarreau240afa62005-12-17 13:14:35 +01004848 */
willy tarreau9e138862006-05-14 23:06:28 +02004849 ptr = del_colon;
willy tarreau240afa62005-12-17 13:14:35 +01004850 }
4851 else
4852 delete_header = 1;
4853 }
4854 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004855
4856 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004857 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01004858 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau9e138862006-05-14 23:06:28 +02004859 /* WARNING: ptr is not valid anymore, since the header may have
4860 * been deleted or truncated ! */
4861 } else {
4862 /* try to catch the first line as the request */
4863 if (t->req_line.len < 0) {
4864 t->req_line.str = req->h;
4865 t->req_line.len = ptr - req->h;
4866 }
4867
4868 /* We might also need the 'Authorization: ' header */
4869 if (t->auth_hdr.len < 0 &&
4870 t->proxy->uri_auth != NULL &&
4871 ptr > req->h + 15 &&
4872 !strncasecmp("Authorization: ", req->h, 15)) {
4873 t->auth_hdr.str = req->h;
4874 t->auth_hdr.len = ptr - req->h;
4875 }
willy tarreau0f7af912005-12-17 12:21:26 +01004876 }
willy tarreau240afa62005-12-17 13:14:35 +01004877
willy tarreau5cbea6f2005-12-17 12:48:26 +01004878 req->h = req->lr;
4879 } /* while (req->lr < req->r) */
4880
4881 /* end of header processing (even if incomplete) */
4882
willy tarreauef900ab2005-12-17 12:52:52 +01004883 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4884 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4885 * full. We cannot loop here since event_cli_read will disable it only if
4886 * req->l == rlim-data
4887 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004888 FD_SET(t->cli_fd, StaticReadEvent);
4889 if (t->proxy->clitimeout)
4890 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4891 else
4892 tv_eternity(&t->crexpire);
4893 }
4894
willy tarreaue39cd132005-12-17 13:00:18 +01004895 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01004896 * won't be able to free more later, so the session will never terminate.
4897 */
willy tarreaue39cd132005-12-17 13:00:18 +01004898 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01004899 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01004900 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01004901 if (!(t->flags & SN_ERR_MASK))
4902 t->flags |= SN_ERR_PRXCOND;
4903 if (!(t->flags & SN_FINST_MASK))
4904 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004905 return 1;
4906 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004907 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004908 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004909 tv_eternity(&t->crexpire);
4910 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004911 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004912 if (!(t->flags & SN_ERR_MASK))
4913 t->flags |= SN_ERR_CLICL;
4914 if (!(t->flags & SN_FINST_MASK))
4915 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004916 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004917 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004918 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4919
4920 /* read timeout : give up with an error message.
4921 */
4922 t->logs.status = 408;
4923 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004924 if (!(t->flags & SN_ERR_MASK))
4925 t->flags |= SN_ERR_CLITO;
4926 if (!(t->flags & SN_FINST_MASK))
4927 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004928 return 1;
4929 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004930
4931 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004932 }
4933 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004934 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004935 /* FIXME: this error handling is partly buggy because we always report
4936 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4937 * or HEADER phase. BTW, it's not logical to expire the client while
4938 * we're waiting for the server to connect.
4939 */
willy tarreau0f7af912005-12-17 12:21:26 +01004940 /* read or write error */
4941 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004942 tv_eternity(&t->crexpire);
4943 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004944 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004945 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004946 if (!(t->flags & SN_ERR_MASK))
4947 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004948 if (!(t->flags & SN_FINST_MASK)) {
4949 if (t->pend_pos)
4950 t->flags |= SN_FINST_Q;
4951 else if (s == SV_STCONN)
4952 t->flags |= SN_FINST_C;
4953 else
4954 t->flags |= SN_FINST_D;
4955 }
willy tarreau0f7af912005-12-17 12:21:26 +01004956 return 1;
4957 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004958 /* last read, or end of server write */
4959 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004960 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004961 tv_eternity(&t->crexpire);
4962 shutdown(t->cli_fd, SHUT_RD);
4963 t->cli_state = CL_STSHUTR;
4964 return 1;
4965 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004966 /* last server read and buffer empty */
4967 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004968 FD_CLR(t->cli_fd, StaticWriteEvent);
4969 tv_eternity(&t->cwexpire);
4970 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004971 /* We must ensure that the read part is still alive when switching
4972 * to shutw */
4973 FD_SET(t->cli_fd, StaticReadEvent);
4974 if (t->proxy->clitimeout)
4975 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004976 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004977 //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 +01004978 return 1;
4979 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004980 /* read timeout */
4981 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4982 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004983 tv_eternity(&t->crexpire);
4984 shutdown(t->cli_fd, SHUT_RD);
4985 t->cli_state = CL_STSHUTR;
4986 if (!(t->flags & SN_ERR_MASK))
4987 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004988 if (!(t->flags & SN_FINST_MASK)) {
4989 if (t->pend_pos)
4990 t->flags |= SN_FINST_Q;
4991 else if (s == SV_STCONN)
4992 t->flags |= SN_FINST_C;
4993 else
4994 t->flags |= SN_FINST_D;
4995 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004996 return 1;
4997 }
4998 /* write timeout */
4999 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
5000 FD_CLR(t->cli_fd, StaticWriteEvent);
5001 tv_eternity(&t->cwexpire);
5002 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005003 /* We must ensure that the read part is still alive when switching
5004 * to shutw */
5005 FD_SET(t->cli_fd, StaticReadEvent);
5006 if (t->proxy->clitimeout)
5007 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
5008
willy tarreau036e1ce2005-12-17 13:46:33 +01005009 t->cli_state = CL_STSHUTW;
5010 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01005011 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005012 if (!(t->flags & SN_FINST_MASK)) {
5013 if (t->pend_pos)
5014 t->flags |= SN_FINST_Q;
5015 else if (s == SV_STCONN)
5016 t->flags |= SN_FINST_C;
5017 else
5018 t->flags |= SN_FINST_D;
5019 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005020 return 1;
5021 }
willy tarreau0f7af912005-12-17 12:21:26 +01005022
willy tarreauc58fc692005-12-17 14:13:08 +01005023 if (req->l >= req->rlim - req->data) {
5024 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01005025 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01005026 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01005027 FD_CLR(t->cli_fd, StaticReadEvent);
5028 tv_eternity(&t->crexpire);
5029 }
5030 }
5031 else {
willy tarreauef900ab2005-12-17 12:52:52 +01005032 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01005033 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
5034 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01005035 if (!t->proxy->clitimeout ||
5036 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
5037 /* If the client has no timeout, or if the server not ready yet, and we
5038 * know for sure that it can expire, then it's cleaner to disable the
5039 * timeout on the client side so that too low values cannot make the
5040 * sessions abort too early.
5041 */
willy tarreau0f7af912005-12-17 12:21:26 +01005042 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01005043 else
5044 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005045 }
5046 }
5047
5048 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01005049 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005050 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5051 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
5052 tv_eternity(&t->cwexpire);
5053 }
5054 }
5055 else { /* buffer not empty */
5056 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5057 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005058 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005059 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005060 /* FIXME: to prevent the client from expiring read timeouts during writes,
5061 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005062 t->crexpire = t->cwexpire;
5063 }
willy tarreau0f7af912005-12-17 12:21:26 +01005064 else
5065 tv_eternity(&t->cwexpire);
5066 }
5067 }
5068 return 0; /* other cases change nothing */
5069 }
5070 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005071 if (t->res_cw == RES_ERROR) {
5072 tv_eternity(&t->cwexpire);
5073 fd_delete(t->cli_fd);
5074 t->cli_state = CL_STCLOSE;
5075 if (!(t->flags & SN_ERR_MASK))
5076 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02005077 if (!(t->flags & SN_FINST_MASK)) {
5078 if (t->pend_pos)
5079 t->flags |= SN_FINST_Q;
5080 else if (s == SV_STCONN)
5081 t->flags |= SN_FINST_C;
5082 else
5083 t->flags |= SN_FINST_D;
5084 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005085 return 1;
5086 }
willy tarreaue0331262006-05-15 03:02:46 +02005087 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
5088 && !(t->flags & SN_SELF_GEN)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005089 tv_eternity(&t->cwexpire);
5090 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005091 t->cli_state = CL_STCLOSE;
5092 return 1;
5093 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005094 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
5095 tv_eternity(&t->cwexpire);
5096 fd_delete(t->cli_fd);
5097 t->cli_state = CL_STCLOSE;
5098 if (!(t->flags & SN_ERR_MASK))
5099 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005100 if (!(t->flags & SN_FINST_MASK)) {
5101 if (t->pend_pos)
5102 t->flags |= SN_FINST_Q;
5103 else if (s == SV_STCONN)
5104 t->flags |= SN_FINST_C;
5105 else
5106 t->flags |= SN_FINST_D;
5107 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005108 return 1;
5109 }
willy tarreaue0331262006-05-15 03:02:46 +02005110
5111 if (t->flags & SN_SELF_GEN) {
5112 produce_content(t);
5113 if (rep->l == 0) {
5114 tv_eternity(&t->cwexpire);
5115 fd_delete(t->cli_fd);
5116 t->cli_state = CL_STCLOSE;
5117 return 1;
5118 }
5119 }
5120
5121 if ((rep->l == 0)
5122 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005123 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5124 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
5125 tv_eternity(&t->cwexpire);
5126 }
5127 }
5128 else { /* buffer not empty */
5129 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5130 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005131 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005132 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005133 /* FIXME: to prevent the client from expiring read timeouts during writes,
5134 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005135 t->crexpire = t->cwexpire;
5136 }
willy tarreau0f7af912005-12-17 12:21:26 +01005137 else
5138 tv_eternity(&t->cwexpire);
5139 }
5140 }
5141 return 0;
5142 }
5143 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005144 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005145 tv_eternity(&t->crexpire);
5146 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005147 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005148 if (!(t->flags & SN_ERR_MASK))
5149 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02005150 if (!(t->flags & SN_FINST_MASK)) {
5151 if (t->pend_pos)
5152 t->flags |= SN_FINST_Q;
5153 else if (s == SV_STCONN)
5154 t->flags |= SN_FINST_C;
5155 else
5156 t->flags |= SN_FINST_D;
5157 }
willy tarreau0f7af912005-12-17 12:21:26 +01005158 return 1;
5159 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005160 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
5161 tv_eternity(&t->crexpire);
5162 fd_delete(t->cli_fd);
5163 t->cli_state = CL_STCLOSE;
5164 return 1;
5165 }
5166 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
5167 tv_eternity(&t->crexpire);
5168 fd_delete(t->cli_fd);
5169 t->cli_state = CL_STCLOSE;
5170 if (!(t->flags & SN_ERR_MASK))
5171 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005172 if (!(t->flags & SN_FINST_MASK)) {
5173 if (t->pend_pos)
5174 t->flags |= SN_FINST_Q;
5175 else if (s == SV_STCONN)
5176 t->flags |= SN_FINST_C;
5177 else
5178 t->flags |= SN_FINST_D;
5179 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005180 return 1;
5181 }
willy tarreauef900ab2005-12-17 12:52:52 +01005182 else if (req->l >= req->rlim - req->data) {
5183 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01005184
5185 /* FIXME-20050705: is it possible for a client to maintain a session
5186 * after the timeout by sending more data after it receives a close ?
5187 */
5188
willy tarreau0f7af912005-12-17 12:21:26 +01005189 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01005190 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01005191 FD_CLR(t->cli_fd, StaticReadEvent);
5192 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01005193 //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 +01005194 }
5195 }
5196 else {
willy tarreauef900ab2005-12-17 12:52:52 +01005197 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01005198 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
5199 FD_SET(t->cli_fd, StaticReadEvent);
5200 if (t->proxy->clitimeout)
5201 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
5202 else
5203 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01005204 //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 +01005205 }
5206 }
5207 return 0;
5208 }
5209 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005210 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005211 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005212 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 +01005213 write(1, trash, len);
5214 }
5215 return 0;
5216 }
5217 return 0;
5218}
5219
willy tarreaudfece232006-05-02 00:19:57 +02005220/* This function turns the server state into the SV_STCLOSE, and sets
5221 * indicators accordingly. Note that if <status> is 0, no message is
5222 * returned.
5223 */
5224void srv_close_with_err(struct session *t, int err, int finst, int status, int msglen, char *msg) {
5225 t->srv_state = SV_STCLOSE;
5226 if (status > 0) {
5227 t->logs.status = status;
5228 if (t->proxy->mode == PR_MODE_HTTP)
5229 client_return(t, msglen, msg);
5230 }
5231 if (!(t->flags & SN_ERR_MASK))
5232 t->flags |= err;
5233 if (!(t->flags & SN_FINST_MASK))
5234 t->flags |= finst;
5235}
5236
5237/*
5238 * This function checks the retry count during the connect() job.
5239 * It updates the session's srv_state and retries, so that the caller knows
5240 * what it has to do. It uses the last connection error to set the log when
5241 * it expires. It returns 1 when it has expired, and 0 otherwise.
5242 */
5243int srv_count_retry_down(struct session *t, int conn_err) {
5244 /* we are in front of a retryable error */
5245 t->conn_retries--;
5246 if (t->conn_retries < 0) {
5247 /* if not retryable anymore, let's abort */
5248 tv_eternity(&t->cnexpire);
5249 srv_close_with_err(t, conn_err, SN_FINST_C,
5250 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaue3b30652006-05-21 16:23:22 +02005251 if (t->srv)
5252 t->srv->failed_conns++;
5253 t->proxy->failed_conns++;
5254
willy tarreaudfece232006-05-02 00:19:57 +02005255 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005256 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005257 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005258 if (may_dequeue_tasks(t->srv, t->proxy))
5259 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005260 return 1;
5261 }
5262 return 0;
5263}
willy tarreau0f7af912005-12-17 12:21:26 +01005264
5265/*
willy tarreaudfece232006-05-02 00:19:57 +02005266 * This function performs the retryable part of the connect() job.
5267 * It updates the session's srv_state and retries, so that the caller knows
5268 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
5269 * it needs to redispatch.
5270 */
5271int srv_retryable_connect(struct session *t) {
5272 int conn_err;
5273
5274 /* This loop ensures that we stop before the last retry in case of a
5275 * redispatchable server.
5276 */
5277 do {
5278 /* initiate a connection to the server */
5279 conn_err = connect_server(t);
5280 switch (conn_err) {
5281
5282 case SN_ERR_NONE:
5283 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
5284 t->srv_state = SV_STCONN;
5285 return 1;
5286
5287 case SN_ERR_INTERNAL:
5288 tv_eternity(&t->cnexpire);
5289 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
5290 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreaue3b30652006-05-21 16:23:22 +02005291 if (t->srv)
5292 t->srv->failed_conns++;
5293 t->proxy->failed_conns++;
willy tarreaudfece232006-05-02 00:19:57 +02005294 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02005295 if (may_dequeue_tasks(t->srv, t->proxy))
5296 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005297 return 1;
5298 }
5299 /* ensure that we have enough retries left */
willy tarreau59a6cc22006-05-12 01:29:08 +02005300 if (srv_count_retry_down(t, conn_err)) {
5301 /* 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);
willy tarreaudfece232006-05-02 00:19:57 +02005304 return 1;
willy tarreau59a6cc22006-05-12 01:29:08 +02005305 }
willy tarreaudfece232006-05-02 00:19:57 +02005306 } while (t->srv == NULL || t->conn_retries > 0 || !(t->proxy->options & PR_O_REDISP));
5307
5308 /* We're on our last chance, and the REDISP option was specified.
5309 * We will ignore cookie and force to balance or use the dispatcher.
5310 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005311 /* let's try to offer this slot to anybody */
5312 if (may_dequeue_tasks(t->srv, t->proxy))
5313 task_wakeup(&rq, t->srv->queue_mgt);
5314
willy tarreaue3b30652006-05-21 16:23:22 +02005315 if (t->srv)
5316 t->srv->failed_conns++;
5317 t->proxy->failed_conns++;
5318
willy tarreaudfece232006-05-02 00:19:57 +02005319 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
5320 t->srv = NULL; /* it's left to the dispatcher to choose a server */
5321 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
5322 t->flags &= ~SN_CK_MASK;
5323 t->flags |= SN_CK_DOWN;
5324 }
5325 return 0;
5326}
5327
5328/* This function performs the "redispatch" part of a connection attempt. It
5329 * will assign a server if required, queue the connection if required, and
5330 * handle errors that might arise at this level. It can change the server
5331 * state. It will return 1 if it encounters an error, switches the server
5332 * state, or has to queue a connection. Otherwise, it will return 0 indicating
5333 * that the connection is ready to use.
5334 */
5335
5336int srv_redispatch_connect(struct session *t) {
5337 int conn_err;
5338
5339 /* We know that we don't have any connection pending, so we will
5340 * try to get a new one, and wait in this state if it's queued
5341 */
5342 conn_err = assign_server_and_queue(t);
5343 switch (conn_err) {
5344 case SRV_STATUS_OK:
5345 break;
5346
5347 case SRV_STATUS_NOSRV:
willy tarreau59a6cc22006-05-12 01:29:08 +02005348 /* note: it is guaranteed that t->srv == NULL here */
willy tarreaudfece232006-05-02 00:19:57 +02005349 tv_eternity(&t->cnexpire);
5350 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
5351 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaue3b30652006-05-21 16:23:22 +02005352 if (t->srv)
5353 t->srv->failed_conns++;
5354 t->proxy->failed_conns++;
5355
willy tarreaudfece232006-05-02 00:19:57 +02005356 return 1;
5357
5358 case SRV_STATUS_QUEUED:
willy tarreau45526ed2006-05-03 20:11:50 +02005359 /* FIXME-20060503 : we should use the queue timeout instead */
5360 if (t->proxy->contimeout)
5361 tv_delayfrom(&t->cnexpire, &now, t->proxy->contimeout);
5362 else
5363 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02005364 t->srv_state = SV_STIDLE;
5365 /* do nothing else and do not wake any other session up */
5366 return 1;
5367
5368 case SRV_STATUS_FULL:
5369 case SRV_STATUS_INTERNAL:
5370 default:
5371 tv_eternity(&t->cnexpire);
5372 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
5373 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreaue3b30652006-05-21 16:23:22 +02005374 if (t->srv)
5375 t->srv->failed_conns++;
5376 t->proxy->failed_conns++;
5377
willy tarreaudfece232006-05-02 00:19:57 +02005378 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02005379 if (may_dequeue_tasks(t->srv, t->proxy))
5380 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005381 return 1;
5382 }
5383 /* if we get here, it's because we got SRV_STATUS_OK, which also
5384 * means that the connection has not been queued.
5385 */
5386 return 0;
5387}
5388
5389
5390/*
willy tarreau0f7af912005-12-17 12:21:26 +01005391 * manages the server FSM and its socket. It returns 1 if a state has changed
5392 * (and a resync may be needed), 0 else.
5393 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005394int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01005395 int s = t->srv_state;
5396 int c = t->cli_state;
5397 struct buffer *req = t->req;
5398 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01005399 appsess *asession_temp = NULL;
5400 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01005401 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01005402
willy tarreau750a4722005-12-17 13:21:24 +01005403#ifdef DEBUG_FULL
5404 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
5405#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01005406 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
5407 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
5408 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
5409 //);
willy tarreau0f7af912005-12-17 12:21:26 +01005410 if (s == SV_STIDLE) {
5411 if (c == CL_STHEADERS)
5412 return 0; /* stay in idle, waiting for data to reach the client side */
willy tarreau03a92de2006-05-21 18:26:53 +02005413 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
5414 (c == CL_STSHUTR &&
5415 (t->req->l == 0 || t->proxy->options & PR_O_ABRT_CLOSE))) { /* give up */
willy tarreau0f7af912005-12-17 12:21:26 +01005416 tv_eternity(&t->cnexpire);
willy tarreau424e04a2006-05-13 16:08:47 +02005417 if (t->pend_pos)
5418 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreau51e91292006-05-14 23:29:47 +02005419 /* note that this must not return any error because it would be able to
5420 * overwrite the client_retnclose() output.
5421 */
willy tarreau078c79a2006-05-13 12:23:58 +02005422 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 +02005423
willy tarreau0f7af912005-12-17 12:21:26 +01005424 return 1;
5425 }
willy tarreaudfece232006-05-02 00:19:57 +02005426 else {
5427 /* Right now, we will need to create a connection to the server.
5428 * We might already have tried, and got a connection pending, in
5429 * which case we will not do anything till it's pending. It's up
5430 * to any other session to release it and wake us up again.
5431 */
willy tarreau45526ed2006-05-03 20:11:50 +02005432 if (t->pend_pos) {
5433 if (tv_cmp2_ms(&t->cnexpire, &now) > 0)
5434 return 0;
5435 else {
5436 /* we've been waiting too long here */
5437 tv_eternity(&t->cnexpire);
willy tarreau078c79a2006-05-13 12:23:58 +02005438 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
5439 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
willy tarreau45526ed2006-05-03 20:11:50 +02005440 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaue3b30652006-05-21 16:23:22 +02005441 if (t->srv)
5442 t->srv->failed_conns++;
5443 t->proxy->failed_conns++;
willy tarreau45526ed2006-05-03 20:11:50 +02005444 return 1;
5445 }
5446 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005447
willy tarreaudfece232006-05-02 00:19:57 +02005448 do {
5449 /* first, get a connection */
5450 if (srv_redispatch_connect(t))
5451 return t->srv_state != SV_STIDLE;
5452
5453 /* try to (re-)connect to the server, and fail if we expire the
5454 * number of retries.
5455 */
willy tarreauf32f5242006-05-02 22:54:52 +02005456 if (srv_retryable_connect(t)) {
5457 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02005458 return t->srv_state != SV_STIDLE;
willy tarreauf32f5242006-05-02 22:54:52 +02005459 }
willy tarreaudfece232006-05-02 00:19:57 +02005460
5461 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01005462 }
5463 }
5464 else if (s == SV_STCONN) { /* connection in progress */
willy tarreau03a92de2006-05-21 18:26:53 +02005465 if (c == CL_STCLOSE || c == CL_STSHUTW ||
5466 (c == CL_STSHUTR &&
5467 (t->req->l == 0 || t->proxy->options & PR_O_ABRT_CLOSE))) { /* give up */
5468 tv_eternity(&t->cnexpire);
5469 fd_delete(t->srv_fd);
5470 if (t->srv)
5471 t->srv->cur_sess--;
5472
5473 /* note that this must not return any error because it would be able to
5474 * overwrite the client_retnclose() output.
5475 */
5476 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, 0, NULL);
5477 return 1;
5478 }
willy tarreau0f7af912005-12-17 12:21:26 +01005479 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01005480 //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 +01005481 return 0; /* nothing changed */
5482 }
5483 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
willy tarreaudfece232006-05-02 00:19:57 +02005484 /* timeout, asynchronous connect error or first write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005485 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
willy tarreaudfece232006-05-02 00:19:57 +02005486
willy tarreau0f7af912005-12-17 12:21:26 +01005487 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005488 if (t->srv)
5489 t->srv->cur_sess--;
willy tarreaudfece232006-05-02 00:19:57 +02005490
5491 if (t->res_sw == RES_SILENT)
willy tarreaub1285d52005-12-18 01:20:14 +01005492 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
5493 else
willy tarreaudfece232006-05-02 00:19:57 +02005494 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
willy tarreaub1285d52005-12-18 01:20:14 +01005495
willy tarreaudfece232006-05-02 00:19:57 +02005496 /* ensure that we have enough retries left */
5497 if (srv_count_retry_down(t, conn_err))
5498 return 1;
5499
5500 do {
5501 /* Now we will try to either reconnect to the same server or
5502 * connect to another server. If the connection gets queued
5503 * because all servers are saturated, then we will go back to
5504 * the SV_STIDLE state.
5505 */
willy tarreauf32f5242006-05-02 22:54:52 +02005506 if (srv_retryable_connect(t)) {
5507 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02005508 return t->srv_state != SV_STCONN;
willy tarreauf32f5242006-05-02 22:54:52 +02005509 }
willy tarreaudfece232006-05-02 00:19:57 +02005510
5511 /* we need to redispatch the connection to another server */
5512 if (srv_redispatch_connect(t))
5513 return t->srv_state != SV_STCONN;
5514 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01005515 }
5516 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01005517 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005518
willy tarreau0f7af912005-12-17 12:21:26 +01005519 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005520 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01005521 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005522 tv_eternity(&t->swexpire);
5523 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01005524 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005525 if (t->proxy->srvtimeout) {
5526 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005527 /* FIXME: to prevent the server from expiring read timeouts during writes,
5528 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005529 t->srexpire = t->swexpire;
5530 }
5531 else
5532 tv_eternity(&t->swexpire);
5533 }
willy tarreau0f7af912005-12-17 12:21:26 +01005534
5535 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
5536 FD_SET(t->srv_fd, StaticReadEvent);
5537 if (t->proxy->srvtimeout)
5538 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5539 else
5540 tv_eternity(&t->srexpire);
5541
5542 t->srv_state = SV_STDATA;
willy tarreau2d505e52006-05-21 08:32:50 +02005543 if (t->srv)
5544 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01005545 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01005546
5547 /* if the user wants to log as soon as possible, without counting
5548 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005549 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005550 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
5551 sess_log(t);
5552 }
willy tarreau0f7af912005-12-17 12:21:26 +01005553 }
willy tarreauef900ab2005-12-17 12:52:52 +01005554 else {
willy tarreau0f7af912005-12-17 12:21:26 +01005555 t->srv_state = SV_STHEADERS;
willy tarreau2d505e52006-05-21 08:32:50 +02005556 if (t->srv)
5557 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01005558 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
5559 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005560 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005561 return 1;
5562 }
5563 }
5564 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005565 /* now parse the partial (or complete) headers */
5566 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
5567 char *ptr;
5568 int delete_header;
5569
5570 ptr = rep->lr;
5571
5572 /* look for the end of the current header */
5573 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
5574 ptr++;
5575
5576 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005577 int line, len;
5578
5579 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01005580
5581 /* first, we'll block if security checks have caught nasty things */
5582 if (t->flags & SN_CACHEABLE) {
5583 if ((t->flags & SN_CACHE_COOK) &&
5584 (t->flags & SN_SCK_ANY) &&
5585 (t->proxy->options & PR_O_CHK_CACHE)) {
5586
5587 /* we're in presence of a cacheable response containing
5588 * a set-cookie header. We'll block it as requested by
5589 * the 'checkcache' option, and send an alert.
5590 */
5591 tv_eternity(&t->srexpire);
5592 tv_eternity(&t->swexpire);
5593 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02005594 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02005595 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02005596 t->srv->failed_secu++;
5597 }
5598 t->proxy->failed_secu++;
willy tarreau97f58572005-12-18 00:53:44 +01005599 t->srv_state = SV_STCLOSE;
5600 t->logs.status = 502;
5601 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
5602 if (!(t->flags & SN_ERR_MASK))
5603 t->flags |= SN_ERR_PRXCOND;
5604 if (!(t->flags & SN_FINST_MASK))
5605 t->flags |= SN_FINST_H;
5606
5607 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
5608 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
5609
willy tarreaudfece232006-05-02 00:19:57 +02005610 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005611 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005612 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005613 if (may_dequeue_tasks(t->srv, t->proxy))
5614 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005615
willy tarreau97f58572005-12-18 00:53:44 +01005616 return 1;
5617 }
5618 }
5619
willy tarreau982249e2005-12-18 00:57:06 +01005620 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
5621 if (t->flags & SN_SVDENY) {
5622 tv_eternity(&t->srexpire);
5623 tv_eternity(&t->swexpire);
5624 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02005625 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02005626 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02005627 t->srv->failed_secu++;
5628 }
5629 t->proxy->failed_secu++;
willy tarreau982249e2005-12-18 00:57:06 +01005630 t->srv_state = SV_STCLOSE;
5631 t->logs.status = 502;
5632 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
5633 if (!(t->flags & SN_ERR_MASK))
5634 t->flags |= SN_ERR_PRXCOND;
5635 if (!(t->flags & SN_FINST_MASK))
5636 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005637 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005638 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005639 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005640 if (may_dequeue_tasks(t->srv, t->proxy))
5641 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005642
willy tarreau982249e2005-12-18 00:57:06 +01005643 return 1;
5644 }
5645
willy tarreau5cbea6f2005-12-17 12:48:26 +01005646 /* we'll have something else to do here : add new headers ... */
5647
willy tarreaucd878942005-12-17 13:27:43 +01005648 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
5649 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005650 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01005651 * insert a set-cookie here, except if we want to insert only on POST
willy tarreau4f7a1012006-05-09 23:32:26 +02005652 * requests and this one isn't. Note that servers which don't have cookies
5653 * (eg: some backup servers) will return a full cookie removal request.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005654 */
willy tarreau750a4722005-12-17 13:21:24 +01005655 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01005656 t->proxy->cookie_name,
willy tarreau4f7a1012006-05-09 23:32:26 +02005657 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
willy tarreau750a4722005-12-17 13:21:24 +01005658
willy tarreau036e1ce2005-12-17 13:46:33 +01005659 t->flags |= SN_SCK_INSERTED;
5660
willy tarreau750a4722005-12-17 13:21:24 +01005661 /* Here, we will tell an eventual cache on the client side that we don't
5662 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
5663 * Some caches understand the correct form: 'no-cache="set-cookie"', but
5664 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
5665 */
willy tarreau240afa62005-12-17 13:14:35 +01005666 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01005667 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
5668 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01005669
5670 if (rep->data + rep->l < rep->h)
5671 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
5672 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01005673 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005674 }
5675
5676 /* headers to be added */
5677 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01005678 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
5679 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005680 }
5681
willy tarreau25c4ea52005-12-18 00:49:49 +01005682 /* add a "connection: close" line if needed */
5683 if (t->proxy->options & PR_O_HTTP_CLOSE)
5684 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
5685
willy tarreau5cbea6f2005-12-17 12:48:26 +01005686 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01005687 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01005688 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01005689
Willy TARREAU767ba712006-03-01 22:40:50 +01005690 /* client connection already closed or option 'httpclose' required :
5691 * we close the server's outgoing connection right now.
5692 */
5693 if ((req->l == 0) &&
5694 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
5695 FD_CLR(t->srv_fd, StaticWriteEvent);
5696 tv_eternity(&t->swexpire);
5697
5698 /* We must ensure that the read part is still alive when switching
5699 * to shutw */
5700 FD_SET(t->srv_fd, StaticReadEvent);
5701 if (t->proxy->srvtimeout)
5702 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5703
5704 shutdown(t->srv_fd, SHUT_WR);
5705 t->srv_state = SV_STSHUTW;
5706 }
5707
willy tarreau25c4ea52005-12-18 00:49:49 +01005708 /* if the user wants to log as soon as possible, without counting
5709 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005710 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005711 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
5712 t->logs.bytes = rep->h - rep->data;
5713 sess_log(t);
5714 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005715 break;
5716 }
5717
5718 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
5719 if (ptr > rep->r - 2) {
5720 /* this is a partial header, let's wait for more to come */
5721 rep->lr = ptr;
5722 break;
5723 }
5724
5725 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
5726 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
5727
5728 /* now we know that *ptr is either \r or \n,
5729 * and that there are at least 1 char after it.
5730 */
5731 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
5732 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
5733 else
5734 rep->lr = ptr + 2; /* \r\n or \n\r */
5735
5736 /*
5737 * now we know that we have a full header ; we can do whatever
5738 * we want with these pointers :
5739 * rep->h = beginning of header
5740 * ptr = end of header (first \r or \n)
5741 * rep->lr = beginning of next line (next rep->h)
5742 * rep->r = end of data (not used at this stage)
5743 */
5744
willy tarreaua1598082005-12-17 13:08:06 +01005745
willy tarreau982249e2005-12-18 00:57:06 +01005746 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01005747 t->logs.logwait &= ~LW_RESP;
5748 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01005749 switch (t->logs.status) {
5750 case 200:
5751 case 203:
5752 case 206:
5753 case 300:
5754 case 301:
5755 case 410:
5756 /* RFC2616 @13.4:
5757 * "A response received with a status code of
5758 * 200, 203, 206, 300, 301 or 410 MAY be stored
5759 * by a cache (...) unless a cache-control
5760 * directive prohibits caching."
5761 *
5762 * RFC2616 @9.5: POST method :
5763 * "Responses to this method are not cacheable,
5764 * unless the response includes appropriate
5765 * Cache-Control or Expires header fields."
5766 */
willy tarreau7476ec92006-05-21 16:24:15 +02005767 if (!(t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
willy tarreau982249e2005-12-18 00:57:06 +01005768 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
5769 break;
5770 default:
5771 break;
5772 }
willy tarreau4302f492005-12-18 01:00:37 +01005773 }
5774 else if (t->logs.logwait & LW_RSPHDR) {
5775 struct cap_hdr *h;
5776 int len;
5777 for (h = t->proxy->rsp_cap; h; h = h->next) {
5778 if ((h->namelen + 2 <= ptr - rep->h) &&
5779 (rep->h[h->namelen] == ':') &&
5780 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
5781
5782 if (t->rsp_cap[h->index] == NULL)
5783 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
5784
5785 len = ptr - (rep->h + h->namelen + 2);
5786 if (len > h->len)
5787 len = h->len;
5788
5789 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
5790 t->rsp_cap[h->index][len]=0;
5791 }
5792 }
5793
willy tarreaua1598082005-12-17 13:08:06 +01005794 }
5795
willy tarreau5cbea6f2005-12-17 12:48:26 +01005796 delete_header = 0;
5797
willy tarreau982249e2005-12-18 00:57:06 +01005798 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005799 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01005800 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 +01005801 max = ptr - rep->h;
5802 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01005803 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005804 trash[len++] = '\n';
5805 write(1, trash, len);
5806 }
5807
willy tarreau25c4ea52005-12-18 00:49:49 +01005808 /* remove "connection: " if needed */
5809 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
5810 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
5811 delete_header = 1;
5812 }
5813
willy tarreau5cbea6f2005-12-17 12:48:26 +01005814 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01005815 if (!delete_header && t->proxy->rsp_exp != NULL
5816 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01005817 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005818 char term;
5819
5820 term = *ptr;
5821 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01005822 exp = t->proxy->rsp_exp;
5823 do {
5824 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
5825 switch (exp->action) {
5826 case ACT_ALLOW:
5827 if (!(t->flags & SN_SVDENY))
5828 t->flags |= SN_SVALLOW;
5829 break;
5830 case ACT_REPLACE:
5831 if (!(t->flags & SN_SVDENY)) {
5832 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
5833 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
5834 }
5835 break;
5836 case ACT_REMOVE:
5837 if (!(t->flags & SN_SVDENY))
5838 delete_header = 1;
5839 break;
5840 case ACT_DENY:
5841 if (!(t->flags & SN_SVALLOW))
5842 t->flags |= SN_SVDENY;
5843 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01005844 case ACT_PASS: /* we simply don't deny this one */
5845 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005846 }
5847 break;
5848 }
willy tarreaue39cd132005-12-17 13:00:18 +01005849 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005850 *ptr = term; /* restore the string terminator */
5851 }
5852
willy tarreau97f58572005-12-18 00:53:44 +01005853 /* check for cache-control: or pragma: headers */
5854 if (!delete_header && (t->flags & SN_CACHEABLE)) {
5855 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
5856 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5857 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
5858 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01005859 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01005860 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5861 else {
5862 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01005863 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005864 t->flags &= ~SN_CACHE_COOK;
5865 }
5866 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005867 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005868 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005869 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01005870 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5871 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005872 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01005873 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01005874 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
5875 (rep->h + 25 == ptr || rep->h[25] == ',')) {
5876 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5877 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
5878 (rep->h + 21 == ptr || rep->h[21] == ',')) {
5879 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01005880 }
5881 }
5882 }
5883
willy tarreau5cbea6f2005-12-17 12:48:26 +01005884 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01005885 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01005886 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01005887 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005888 char *p1, *p2, *p3, *p4;
5889
willy tarreau97f58572005-12-18 00:53:44 +01005890 t->flags |= SN_SCK_ANY;
5891
willy tarreau5cbea6f2005-12-17 12:48:26 +01005892 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
5893
5894 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01005895 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005896 p1++;
5897
5898 if (p1 == ptr || *p1 == ';') /* end of cookie */
5899 break;
5900
5901 /* p1 is at the beginning of the cookie name */
5902 p2 = p1;
5903
5904 while (p2 < ptr && *p2 != '=' && *p2 != ';')
5905 p2++;
5906
5907 if (p2 == ptr || *p2 == ';') /* next cookie */
5908 break;
5909
5910 p3 = p2 + 1; /* skips the '=' sign */
5911 if (p3 == ptr)
5912 break;
5913
5914 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01005915 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01005916 p4++;
5917
5918 /* here, we have the cookie name between p1 and p2,
5919 * and its value between p3 and p4.
5920 * we can process it.
5921 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005922
5923 /* first, let's see if we want to capture it */
5924 if (t->proxy->capture_name != NULL &&
5925 t->logs.srv_cookie == NULL &&
5926 (p4 - p1 >= t->proxy->capture_namelen) &&
5927 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
5928 int log_len = p4 - p1;
5929
5930 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
5931 Alert("HTTP logging : out of memory.\n");
5932 }
5933
5934 if (log_len > t->proxy->capture_len)
5935 log_len = t->proxy->capture_len;
5936 memcpy(t->logs.srv_cookie, p1, log_len);
5937 t->logs.srv_cookie[log_len] = 0;
5938 }
5939
5940 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
5941 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005942 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01005943 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005944
5945 /* If the cookie is in insert mode on a known server, we'll delete
5946 * this occurrence because we'll insert another one later.
5947 * We'll delete it too if the "indirect" option is set and we're in
5948 * a direct access. */
5949 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01005950 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005951 /* this header must be deleted */
5952 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01005953 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005954 }
5955 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
5956 /* replace bytes p3->p4 with the cookie name associated
5957 * with this server since we know it.
5958 */
5959 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01005960 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005961 }
willy tarreau0174f312005-12-18 01:02:42 +01005962 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
5963 /* insert the cookie name associated with this server
5964 * before existing cookie, and insert a delimitor between them..
5965 */
5966 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
5967 p3[t->srv->cklen] = COOKIE_DELIM;
5968 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
5969 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005970 break;
5971 }
willy tarreau12350152005-12-18 01:03:27 +01005972
5973 /* first, let's see if the cookie is our appcookie*/
5974 if ((t->proxy->appsession_name != NULL) &&
5975 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
5976
5977 /* Cool... it's the right one */
5978
willy tarreaub952e1d2005-12-18 01:31:20 +01005979 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01005980 asession_temp = &local_asession;
5981
willy tarreaub952e1d2005-12-18 01:31:20 +01005982 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005983 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5984 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5985 }
5986 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
5987 asession_temp->sessid[t->proxy->appsession_len] = 0;
5988 asession_temp->serverid = NULL;
5989
5990 /* only do insert, if lookup fails */
5991 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
5992 if ((asession_temp = pool_alloc(appsess)) == NULL) {
5993 Alert("Not enought Memory process_srv():asession:calloc().\n");
5994 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
5995 return 0;
5996 }
5997 asession_temp->sessid = local_asession.sessid;
5998 asession_temp->serverid = local_asession.serverid;
5999 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01006000 }/* end if (chtbl_lookup()) */
6001 else {
willy tarreau12350152005-12-18 01:03:27 +01006002 /* free wasted memory */
6003 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01006004 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01006005
willy tarreaub952e1d2005-12-18 01:31:20 +01006006 if (asession_temp->serverid == NULL) {
6007 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01006008 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
6009 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
6010 }
6011 asession_temp->serverid[0] = '\0';
6012 }
6013
willy tarreaub952e1d2005-12-18 01:31:20 +01006014 if (asession_temp->serverid[0] == '\0')
6015 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01006016
6017 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
6018
6019#if defined(DEBUG_HASH)
6020 print_table(&(t->proxy->htbl_proxy));
6021#endif
6022 break;
6023 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006024 else {
6025 // fprintf(stderr,"Ignoring unknown cookie : ");
6026 // write(2, p1, p2-p1);
6027 // fprintf(stderr," = ");
6028 // write(2, p3, p4-p3);
6029 // fprintf(stderr,"\n");
6030 }
6031 break; /* we don't want to loop again since there cannot be another cookie on the same line */
6032 } /* we're now at the end of the cookie value */
6033 } /* end of cookie processing */
6034
willy tarreau97f58572005-12-18 00:53:44 +01006035 /* check for any set-cookie in case we check for cacheability */
6036 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
6037 (t->proxy->options & PR_O_CHK_CACHE) &&
6038 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
6039 t->flags |= SN_SCK_ANY;
6040 }
6041
willy tarreau5cbea6f2005-12-17 12:48:26 +01006042 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01006043 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006044 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01006045
willy tarreau5cbea6f2005-12-17 12:48:26 +01006046 rep->h = rep->lr;
6047 } /* while (rep->lr < rep->r) */
6048
6049 /* end of header processing (even if incomplete) */
6050
willy tarreauef900ab2005-12-17 12:52:52 +01006051 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6052 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
6053 * full. We cannot loop here since event_srv_read will disable it only if
6054 * rep->l == rlim-data
6055 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006056 FD_SET(t->srv_fd, StaticReadEvent);
6057 if (t->proxy->srvtimeout)
6058 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6059 else
6060 tv_eternity(&t->srexpire);
6061 }
willy tarreau0f7af912005-12-17 12:21:26 +01006062
willy tarreau8337c6b2005-12-17 13:41:01 +01006063 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01006064 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01006065 tv_eternity(&t->srexpire);
6066 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006067 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006068 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006069 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006070 t->srv->failed_resp++;
6071 }
6072 t->proxy->failed_resp++;
6073
willy tarreau0f7af912005-12-17 12:21:26 +01006074 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01006075 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01006076 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01006077 if (!(t->flags & SN_ERR_MASK))
6078 t->flags |= SN_ERR_SRVCL;
6079 if (!(t->flags & SN_FINST_MASK))
6080 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02006081 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006082 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006083 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006084 if (may_dequeue_tasks(t->srv, t->proxy))
6085 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006086
willy tarreau0f7af912005-12-17 12:21:26 +01006087 return 1;
6088 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006089 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01006090 * since we are in header mode, if there's no space left for headers, we
6091 * won't be able to free more later, so the session will never terminate.
6092 */
willy tarreau8337c6b2005-12-17 13:41:01 +01006093 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 +01006094 FD_CLR(t->srv_fd, StaticReadEvent);
6095 tv_eternity(&t->srexpire);
6096 shutdown(t->srv_fd, SHUT_RD);
6097 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01006098 //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 +01006099 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006100 }
6101 /* read timeout : return a 504 to the client.
6102 */
6103 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6104 tv_eternity(&t->srexpire);
6105 tv_eternity(&t->swexpire);
6106 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006107 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006108 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006109 t->srv->failed_resp++;
6110 }
6111 t->proxy->failed_resp++;
willy tarreau8337c6b2005-12-17 13:41:01 +01006112 t->srv_state = SV_STCLOSE;
6113 t->logs.status = 504;
6114 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01006115 if (!(t->flags & SN_ERR_MASK))
6116 t->flags |= SN_ERR_SRVTO;
6117 if (!(t->flags & SN_FINST_MASK))
6118 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02006119 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006120 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006121 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006122 if (may_dequeue_tasks(t->srv, t->proxy))
6123 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006124
willy tarreau8337c6b2005-12-17 13:41:01 +01006125 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006126 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006127 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01006128 /* FIXME!!! here, we don't want to switch to SHUTW if the
6129 * client shuts read too early, because we may still have
6130 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01006131 * The side-effect is that if the client completely closes its
6132 * connection during SV_STHEADER, the connection to the server
6133 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01006134 */
willy tarreau036e1ce2005-12-17 13:46:33 +01006135 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01006136 FD_CLR(t->srv_fd, StaticWriteEvent);
6137 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01006138
6139 /* We must ensure that the read part is still alive when switching
6140 * to shutw */
6141 FD_SET(t->srv_fd, StaticReadEvent);
6142 if (t->proxy->srvtimeout)
6143 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6144
willy tarreau0f7af912005-12-17 12:21:26 +01006145 shutdown(t->srv_fd, SHUT_WR);
6146 t->srv_state = SV_STSHUTW;
6147 return 1;
6148 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006149 /* write timeout */
6150 /* FIXME!!! here, we don't want to switch to SHUTW if the
6151 * client shuts read too early, because we may still have
6152 * some work to do on the headers.
6153 */
6154 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
6155 FD_CLR(t->srv_fd, StaticWriteEvent);
6156 tv_eternity(&t->swexpire);
6157 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006158 /* We must ensure that the read part is still alive when switching
6159 * to shutw */
6160 FD_SET(t->srv_fd, StaticReadEvent);
6161 if (t->proxy->srvtimeout)
6162 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6163
6164 /* We must ensure that the read part is still alive when switching
6165 * to shutw */
6166 FD_SET(t->srv_fd, StaticReadEvent);
6167 if (t->proxy->srvtimeout)
6168 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6169
willy tarreau036e1ce2005-12-17 13:46:33 +01006170 t->srv_state = SV_STSHUTW;
6171 if (!(t->flags & SN_ERR_MASK))
6172 t->flags |= SN_ERR_SRVTO;
6173 if (!(t->flags & SN_FINST_MASK))
6174 t->flags |= SN_FINST_H;
6175 return 1;
6176 }
willy tarreau0f7af912005-12-17 12:21:26 +01006177
6178 if (req->l == 0) {
6179 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6180 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6181 tv_eternity(&t->swexpire);
6182 }
6183 }
6184 else { /* client buffer not empty */
6185 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6186 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006187 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006188 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006189 /* FIXME: to prevent the server from expiring read timeouts during writes,
6190 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006191 t->srexpire = t->swexpire;
6192 }
willy tarreau0f7af912005-12-17 12:21:26 +01006193 else
6194 tv_eternity(&t->swexpire);
6195 }
6196 }
6197
willy tarreau5cbea6f2005-12-17 12:48:26 +01006198 /* be nice with the client side which would like to send a complete header
6199 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
6200 * would read all remaining data at once ! The client should not write past rep->lr
6201 * when the server is in header state.
6202 */
6203 //return header_processed;
6204 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01006205 }
6206 else if (s == SV_STDATA) {
6207 /* read or write error */
6208 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01006209 tv_eternity(&t->srexpire);
6210 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006211 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006212 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006213 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006214 t->srv->failed_resp++;
6215 }
6216 t->proxy->failed_resp++;
willy tarreau0f7af912005-12-17 12:21:26 +01006217 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01006218 if (!(t->flags & SN_ERR_MASK))
6219 t->flags |= SN_ERR_SRVCL;
6220 if (!(t->flags & SN_FINST_MASK))
6221 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006222 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006223 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006224 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006225 if (may_dequeue_tasks(t->srv, t->proxy))
6226 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006227
willy tarreau0f7af912005-12-17 12:21:26 +01006228 return 1;
6229 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006230 /* last read, or end of client write */
6231 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01006232 FD_CLR(t->srv_fd, StaticReadEvent);
6233 tv_eternity(&t->srexpire);
6234 shutdown(t->srv_fd, SHUT_RD);
6235 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01006236 //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 +01006237 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01006238 }
6239 /* end of client read and no more data to send */
6240 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
6241 FD_CLR(t->srv_fd, StaticWriteEvent);
6242 tv_eternity(&t->swexpire);
6243 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006244 /* We must ensure that the read part is still alive when switching
6245 * to shutw */
6246 FD_SET(t->srv_fd, StaticReadEvent);
6247 if (t->proxy->srvtimeout)
6248 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6249
willy tarreaua41a8b42005-12-17 14:02:24 +01006250 t->srv_state = SV_STSHUTW;
6251 return 1;
6252 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006253 /* read timeout */
6254 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6255 FD_CLR(t->srv_fd, StaticReadEvent);
6256 tv_eternity(&t->srexpire);
6257 shutdown(t->srv_fd, SHUT_RD);
6258 t->srv_state = SV_STSHUTR;
6259 if (!(t->flags & SN_ERR_MASK))
6260 t->flags |= SN_ERR_SRVTO;
6261 if (!(t->flags & SN_FINST_MASK))
6262 t->flags |= SN_FINST_D;
6263 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006264 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006265 /* write timeout */
6266 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01006267 FD_CLR(t->srv_fd, StaticWriteEvent);
6268 tv_eternity(&t->swexpire);
6269 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006270 /* We must ensure that the read part is still alive when switching
6271 * to shutw */
6272 FD_SET(t->srv_fd, StaticReadEvent);
6273 if (t->proxy->srvtimeout)
6274 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01006275 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01006276 if (!(t->flags & SN_ERR_MASK))
6277 t->flags |= SN_ERR_SRVTO;
6278 if (!(t->flags & SN_FINST_MASK))
6279 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01006280 return 1;
6281 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01006282
6283 /* recompute request time-outs */
6284 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01006285 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6286 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6287 tv_eternity(&t->swexpire);
6288 }
6289 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01006290 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01006291 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6292 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006293 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006294 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006295 /* FIXME: to prevent the server from expiring read timeouts during writes,
6296 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006297 t->srexpire = t->swexpire;
6298 }
willy tarreau0f7af912005-12-17 12:21:26 +01006299 else
6300 tv_eternity(&t->swexpire);
6301 }
6302 }
6303
willy tarreaub1ff9db2005-12-17 13:51:03 +01006304 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01006305 if (rep->l == BUFSIZE) { /* no room to read more data */
6306 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
6307 FD_CLR(t->srv_fd, StaticReadEvent);
6308 tv_eternity(&t->srexpire);
6309 }
6310 }
6311 else {
6312 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6313 FD_SET(t->srv_fd, StaticReadEvent);
6314 if (t->proxy->srvtimeout)
6315 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6316 else
6317 tv_eternity(&t->srexpire);
6318 }
6319 }
6320
6321 return 0; /* other cases change nothing */
6322 }
6323 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006324 if (t->res_sw == RES_ERROR) {
6325 //FD_CLR(t->srv_fd, StaticWriteEvent);
6326 tv_eternity(&t->swexpire);
6327 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006328 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006329 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006330 t->srv->failed_resp++;
6331 }
6332 t->proxy->failed_resp++;
willy tarreau036e1ce2005-12-17 13:46:33 +01006333 //close(t->srv_fd);
6334 t->srv_state = SV_STCLOSE;
6335 if (!(t->flags & SN_ERR_MASK))
6336 t->flags |= SN_ERR_SRVCL;
6337 if (!(t->flags & SN_FINST_MASK))
6338 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006339 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006340 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006341 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006342 if (may_dequeue_tasks(t->srv, t->proxy))
6343 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006344
willy tarreau036e1ce2005-12-17 13:46:33 +01006345 return 1;
6346 }
6347 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006348 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01006349 tv_eternity(&t->swexpire);
6350 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006351 if (t->srv)
6352 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006353 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01006354 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02006355 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006356 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006357 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006358 if (may_dequeue_tasks(t->srv, t->proxy))
6359 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006360
willy tarreau0f7af912005-12-17 12:21:26 +01006361 return 1;
6362 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006363 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
6364 //FD_CLR(t->srv_fd, StaticWriteEvent);
6365 tv_eternity(&t->swexpire);
6366 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006367 if (t->srv)
6368 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006369 //close(t->srv_fd);
6370 t->srv_state = SV_STCLOSE;
6371 if (!(t->flags & SN_ERR_MASK))
6372 t->flags |= SN_ERR_SRVTO;
6373 if (!(t->flags & SN_FINST_MASK))
6374 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006375 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006376 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006377 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006378 if (may_dequeue_tasks(t->srv, t->proxy))
6379 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006380
willy tarreau036e1ce2005-12-17 13:46:33 +01006381 return 1;
6382 }
willy tarreau0f7af912005-12-17 12:21:26 +01006383 else if (req->l == 0) {
6384 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6385 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6386 tv_eternity(&t->swexpire);
6387 }
6388 }
6389 else { /* buffer not empty */
6390 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6391 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006392 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006393 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006394 /* FIXME: to prevent the server from expiring read timeouts during writes,
6395 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006396 t->srexpire = t->swexpire;
6397 }
willy tarreau0f7af912005-12-17 12:21:26 +01006398 else
6399 tv_eternity(&t->swexpire);
6400 }
6401 }
6402 return 0;
6403 }
6404 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006405 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006406 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01006407 tv_eternity(&t->srexpire);
6408 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006409 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006410 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006411 t->srv->failed_resp++;
6412 }
6413 t->proxy->failed_resp++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006414 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01006415 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01006416 if (!(t->flags & SN_ERR_MASK))
6417 t->flags |= SN_ERR_SRVCL;
6418 if (!(t->flags & SN_FINST_MASK))
6419 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006420 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006421 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006422 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006423 if (may_dequeue_tasks(t->srv, t->proxy))
6424 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006425
willy tarreau0f7af912005-12-17 12:21:26 +01006426 return 1;
6427 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006428 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
6429 //FD_CLR(t->srv_fd, StaticReadEvent);
6430 tv_eternity(&t->srexpire);
6431 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006432 if (t->srv)
6433 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006434 //close(t->srv_fd);
6435 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02006436 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006437 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006438 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006439 if (may_dequeue_tasks(t->srv, t->proxy))
6440 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006441
willy tarreau036e1ce2005-12-17 13:46:33 +01006442 return 1;
6443 }
6444 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6445 //FD_CLR(t->srv_fd, StaticReadEvent);
6446 tv_eternity(&t->srexpire);
6447 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006448 if (t->srv)
6449 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006450 //close(t->srv_fd);
6451 t->srv_state = SV_STCLOSE;
6452 if (!(t->flags & SN_ERR_MASK))
6453 t->flags |= SN_ERR_SRVTO;
6454 if (!(t->flags & SN_FINST_MASK))
6455 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006456 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006457 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006458 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006459 if (may_dequeue_tasks(t->srv, t->proxy))
6460 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006461
willy tarreau036e1ce2005-12-17 13:46:33 +01006462 return 1;
6463 }
willy tarreau0f7af912005-12-17 12:21:26 +01006464 else if (rep->l == BUFSIZE) { /* no room to read more data */
6465 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
6466 FD_CLR(t->srv_fd, StaticReadEvent);
6467 tv_eternity(&t->srexpire);
6468 }
6469 }
6470 else {
6471 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6472 FD_SET(t->srv_fd, StaticReadEvent);
6473 if (t->proxy->srvtimeout)
6474 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6475 else
6476 tv_eternity(&t->srexpire);
6477 }
6478 }
6479 return 0;
6480 }
6481 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01006482 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01006483 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01006484 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 +01006485 write(1, trash, len);
6486 }
6487 return 0;
6488 }
6489 return 0;
6490}
6491
6492
willy tarreau5cbea6f2005-12-17 12:48:26 +01006493/* Processes the client and server jobs of a session task, then
6494 * puts it back to the wait queue in a clean state, or
6495 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01006496 * the time the task accepts to wait, or TIME_ETERNITY for
6497 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01006498 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006499int process_session(struct task *t) {
6500 struct session *s = t->context;
6501 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006502
willy tarreau5cbea6f2005-12-17 12:48:26 +01006503 do {
6504 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01006505 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006506 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01006507 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006508 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01006509 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006510 } while (fsm_resync);
6511
6512 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01006513 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006514 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01006515
willy tarreau5cbea6f2005-12-17 12:48:26 +01006516 tv_min(&min1, &s->crexpire, &s->cwexpire);
6517 tv_min(&min2, &s->srexpire, &s->swexpire);
6518 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01006519 tv_min(&t->expire, &min1, &min2);
6520
6521 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006522 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01006523
Willy TARREAU1cec83c2006-03-01 22:33:49 +01006524#ifdef DEBUG_FULL
6525 /* DEBUG code : this should never ever happen, otherwise it indicates
6526 * that a task still has something to do and will provoke a quick loop.
6527 */
6528 if (tv_remain2(&now, &t->expire) <= 0)
6529 exit(100);
6530#endif
6531
willy tarreaub952e1d2005-12-18 01:31:20 +01006532 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01006533 }
6534
willy tarreau5cbea6f2005-12-17 12:48:26 +01006535 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01006536 actconn--;
6537
willy tarreau982249e2005-12-18 00:57:06 +01006538 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01006539 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01006540 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 +01006541 write(1, trash, len);
6542 }
6543
willy tarreau750a4722005-12-17 13:21:24 +01006544 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01006545 if (s->rep != NULL)
6546 s->logs.bytes = s->rep->total;
6547
willy tarreau9fe663a2005-12-17 13:02:59 +01006548 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01006549 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01006550 sess_log(s);
6551
willy tarreau0f7af912005-12-17 12:21:26 +01006552 /* the task MUST not be in the run queue anymore */
6553 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006554 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01006555 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01006556 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006557}
6558
6559
willy tarreau2812edc2006-05-04 12:09:37 +02006560/* Sets server <s> down, notifies by all available means, recounts the
6561 * remaining servers on the proxy and transfers queued sessions whenever
6562 * possible to other servers.
6563 */
6564void set_server_down(struct server *s) {
6565 struct pendconn *pc, *pc_bck, *pc_end;
6566 struct session *sess;
6567 int xferred;
6568
6569 s->state &= ~SRV_RUNNING;
6570
6571 if (s->health == s->rise) {
6572 recount_servers(s->proxy);
6573 recalc_server_map(s->proxy);
6574
6575 /* we might have sessions queued on this server and waiting for
6576 * a connection. Those which are redispatchable will be queued
6577 * to another server or to the proxy itself.
6578 */
6579 xferred = 0;
6580 FOREACH_ITEM_SAFE(pc, pc_bck, &s->pendconns, pc_end, struct pendconn *, list) {
6581 sess = pc->sess;
6582 if ((sess->proxy->options & PR_O_REDISP)) {
6583 /* The REDISP option was specified. We will ignore
6584 * cookie and force to balance or use the dispatcher.
6585 */
6586 sess->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
6587 sess->srv = NULL; /* it's left to the dispatcher to choose a server */
6588 if ((sess->flags & SN_CK_MASK) == SN_CK_VALID) {
6589 sess->flags &= ~SN_CK_MASK;
6590 sess->flags |= SN_CK_DOWN;
6591 }
6592 pendconn_free(pc);
6593 task_wakeup(&rq, sess->task);
6594 xferred++;
6595 }
6596 }
6597
6598 sprintf(trash, "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s"
6599 " %d sessions active, %d requeued, %d remaining in queue.\n",
6600 s->state & SRV_BACKUP ? "Backup " : "",
6601 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6602 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6603 s->cur_sess, xferred, s->nbpend);
6604
willy tarreaubc2eda62006-05-04 15:16:23 +02006605 Warning("%s", trash);
6606 send_log(s->proxy, LOG_ALERT, "%s", trash);
willy tarreau2812edc2006-05-04 12:09:37 +02006607
6608 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
6609 Alert("Proxy %s has no server available !\n", s->proxy->id);
6610 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
6611 }
willy tarreaucb406512006-05-18 00:52:35 +02006612 s->down_trans++;
willy tarreau2812edc2006-05-04 12:09:37 +02006613 }
6614 s->health = 0; /* failure */
6615}
6616
6617
willy tarreau5cbea6f2005-12-17 12:48:26 +01006618
6619/*
6620 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01006621 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01006622 */
6623int process_chk(struct task *t) {
6624 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01006625 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01006626 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006627
willy tarreauef900ab2005-12-17 12:52:52 +01006628 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006629
willy tarreau25424f82006-03-19 19:37:48 +01006630 new_chk:
6631 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006632 if (fd < 0) { /* no check currently running */
6633 //fprintf(stderr, "process_chk: 2\n");
6634 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
6635 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006636 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006637 }
Willy TARREAU3759f982006-03-01 22:44:17 +01006638
6639 /* we don't send any health-checks when the proxy is stopped or when
6640 * the server should not be checked.
6641 */
6642 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01006643 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6644 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01006645 task_queue(t); /* restore t to its place in the task list */
6646 return tv_remain2(&now, &t->expire);
6647 }
6648
willy tarreau5cbea6f2005-12-17 12:48:26 +01006649 /* we'll initiate a new check */
6650 s->result = 0; /* no result yet */
6651 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006652 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01006653 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
6654 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
6655 //fprintf(stderr, "process_chk: 3\n");
6656
willy tarreaua41a8b42005-12-17 14:02:24 +01006657 /* we'll connect to the check port on the server */
6658 sa = s->addr;
6659 sa.sin_port = htons(s->check_port);
6660
willy tarreau0174f312005-12-18 01:02:42 +01006661 /* allow specific binding :
6662 * - server-specific at first
6663 * - proxy-specific next
6664 */
6665 if (s->state & SRV_BIND_SRC) {
6666 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
6667 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
6668 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
6669 s->proxy->id, s->id);
6670 s->result = -1;
6671 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006672 }
willy tarreau0174f312005-12-18 01:02:42 +01006673 else if (s->proxy->options & PR_O_BIND_SRC) {
6674 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
6675 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
6676 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
6677 s->proxy->id);
6678 s->result = -1;
6679 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006680 }
willy tarreau0174f312005-12-18 01:02:42 +01006681
6682 if (!s->result) {
6683 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
6684 /* OK, connection in progress or established */
6685
6686 //fprintf(stderr, "process_chk: 4\n");
6687
6688 s->curfd = fd; /* that's how we know a test is in progress ;-) */
6689 fdtab[fd].owner = t;
6690 fdtab[fd].read = &event_srv_chk_r;
6691 fdtab[fd].write = &event_srv_chk_w;
6692 fdtab[fd].state = FD_STCONN; /* connection in progress */
6693 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01006694#ifdef DEBUG_FULL
6695 assert (!FD_ISSET(fd, StaticReadEvent));
6696#endif
willy tarreau0174f312005-12-18 01:02:42 +01006697 fd_insert(fd);
6698 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
6699 tv_delayfrom(&t->expire, &now, s->inter);
6700 task_queue(t); /* restore t to its place in the task list */
6701 return tv_remain(&now, &t->expire);
6702 }
6703 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
6704 s->result = -1; /* a real error */
6705 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006706 }
6707 }
willy tarreau08dedbe2005-12-18 01:13:48 +01006708 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006709 }
6710
6711 if (!s->result) { /* nothing done */
6712 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01006713 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6714 tv_delayfrom(&t->expire, &t->expire, s->inter);
6715 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006716 }
6717
6718 /* here, we have seen a failure */
willy tarreaucb406512006-05-18 00:52:35 +02006719 if (s->health > s->rise) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006720 s->health--; /* still good */
willy tarreaucb406512006-05-18 00:52:35 +02006721 s->failed_checks++;
6722 }
willy tarreau2812edc2006-05-04 12:09:37 +02006723 else
6724 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006725
6726 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01006727 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01006728 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6729 tv_delayfrom(&t->expire, &t->expire, s->inter);
6730 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006731 }
6732 else {
6733 //fprintf(stderr, "process_chk: 8\n");
6734 /* there was a test running */
6735 if (s->result > 0) { /* good server detected */
6736 //fprintf(stderr, "process_chk: 9\n");
6737 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01006738 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02006739 s->state |= SRV_RUNNING;
6740
willy tarreau535ae7a2005-12-17 12:58:00 +01006741 if (s->health == s->rise) {
willy tarreaubc2eda62006-05-04 15:16:23 +02006742 int xferred;
6743
willy tarreau62084d42006-03-24 18:57:41 +01006744 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02006745 recalc_server_map(s->proxy);
willy tarreaubc2eda62006-05-04 15:16:23 +02006746
6747 /* check if we can handle some connections queued at the proxy. We
6748 * will take as many as we can handle.
6749 */
willy tarreauf76e6ca2006-05-21 21:09:55 +02006750 for (xferred = 0; !s->maxconn || xferred < srv_dynamic_maxconn(s); xferred++) {
willy tarreaubc2eda62006-05-04 15:16:23 +02006751 struct session *sess;
6752 struct pendconn *p;
6753
6754 p = pendconn_from_px(s->proxy);
6755 if (!p)
6756 break;
6757 p->sess->srv = s;
6758 sess = p->sess;
6759 pendconn_free(p);
6760 task_wakeup(&rq, sess->task);
6761 }
6762
6763 sprintf(trash,
6764 "%sServer %s/%s is UP. %d active and %d backup servers online.%s"
6765 " %d sessions requeued, %d total in queue.\n",
6766 s->state & SRV_BACKUP ? "Backup " : "",
6767 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6768 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6769 xferred, s->nbpend);
6770
6771 Warning("%s", trash);
6772 send_log(s->proxy, LOG_NOTICE, "%s", trash);
willy tarreau535ae7a2005-12-17 12:58:00 +01006773 }
willy tarreauef900ab2005-12-17 12:52:52 +01006774
willy tarreaue47c8d72005-12-17 12:55:52 +01006775 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006776 }
willy tarreauef900ab2005-12-17 12:52:52 +01006777 s->curfd = -1; /* no check running anymore */
6778 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006779 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006780 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6781 tv_delayfrom(&t->expire, &t->expire, s->inter);
6782 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006783 }
6784 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
6785 //fprintf(stderr, "process_chk: 10\n");
6786 /* failure or timeout detected */
willy tarreaucb406512006-05-18 00:52:35 +02006787 if (s->health > s->rise) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006788 s->health--; /* still good */
willy tarreaucb406512006-05-18 00:52:35 +02006789 s->failed_checks++;
6790 }
willy tarreau2812edc2006-05-04 12:09:37 +02006791 else
6792 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006793 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01006794 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006795 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006796 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6797 tv_delayfrom(&t->expire, &t->expire, s->inter);
6798 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006799 }
6800 /* if result is 0 and there's no timeout, we have to wait again */
6801 }
6802 //fprintf(stderr, "process_chk: 11\n");
6803 s->result = 0;
6804 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006805 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01006806}
6807
6808
willy tarreau5cbea6f2005-12-17 12:48:26 +01006809
willy tarreau59a6cc22006-05-12 01:29:08 +02006810/*
6811 * Manages a server's connection queue. If woken up, will try to dequeue as
6812 * many pending sessions as possible, and wake them up. The task has nothing
6813 * else to do, so it always returns TIME_ETERNITY.
6814 */
6815int process_srv_queue(struct task *t) {
6816 struct server *s = (struct server*)t->context;
6817 struct proxy *p = s->proxy;
6818 int xferred;
6819
6820 /* First, check if we can handle some connections queued at the proxy. We
6821 * will take as many as we can handle.
6822 */
willy tarreauf76e6ca2006-05-21 21:09:55 +02006823 for (xferred = 0; s->cur_sess + xferred < srv_dynamic_maxconn(s); xferred++) {
willy tarreau59a6cc22006-05-12 01:29:08 +02006824 struct session *sess;
6825
6826 sess = pendconn_get_next_sess(s, p);
6827 if (sess == NULL)
6828 break;
6829 task_wakeup(&rq, sess->task);
6830 }
6831
6832 return TIME_ETERNITY;
6833}
6834
willy tarreau0f7af912005-12-17 12:21:26 +01006835#if STATTIME > 0
6836int stats(void);
6837#endif
6838
6839/*
willy tarreau1c2ad212005-12-18 01:11:29 +01006840 * This does 4 things :
6841 * - wake up all expired tasks
6842 * - call all runnable tasks
6843 * - call maintain_proxies() to enable/disable the listeners
6844 * - return the delay till next event in ms, -1 = wait indefinitely
6845 * Note: this part should be rewritten with the O(ln(n)) scheduler.
6846 *
willy tarreau0f7af912005-12-17 12:21:26 +01006847 */
6848
willy tarreau1c2ad212005-12-18 01:11:29 +01006849int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01006850 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01006851 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006852 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01006853
willy tarreaub952e1d2005-12-18 01:31:20 +01006854 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01006855
willy tarreau1c2ad212005-12-18 01:11:29 +01006856 /* look for expired tasks and add them to the run queue.
6857 */
willy tarreau5e698ef2006-05-02 14:51:00 +02006858 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6859 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau1c2ad212005-12-18 01:11:29 +01006860 tnext = t->next;
6861 if (t->state & TASK_RUNNING)
6862 continue;
6863
willy tarreaub952e1d2005-12-18 01:31:20 +01006864 if (tv_iseternity(&t->expire))
6865 continue;
6866
willy tarreau1c2ad212005-12-18 01:11:29 +01006867 /* wakeup expired entries. It doesn't matter if they are
6868 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01006869 */
willy tarreaub952e1d2005-12-18 01:31:20 +01006870 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006871 task_wakeup(&rq, t);
6872 }
6873 else {
6874 /* first non-runnable task. Use its expiration date as an upper bound */
6875 int temp_time = tv_remain(&now, &t->expire);
6876 if (temp_time)
6877 next_time = temp_time;
6878 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006879 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006880 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006881
willy tarreau1c2ad212005-12-18 01:11:29 +01006882 /* process each task in the run queue now. Each task may be deleted
willy tarreau7feab592006-04-22 15:13:16 +02006883 * since we only use the run queue's head. Note that any task can be
6884 * woken up by any other task and it will be processed immediately
6885 * after as it will be queued on the run queue's head.
willy tarreau1c2ad212005-12-18 01:11:29 +01006886 */
willy tarreau7feab592006-04-22 15:13:16 +02006887 while ((t = rq) != NULL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006888 int temp_time;
willy tarreau7feab592006-04-22 15:13:16 +02006889
willy tarreau1c2ad212005-12-18 01:11:29 +01006890 task_sleep(&rq, t);
6891 temp_time = t->process(t);
6892 next_time = MINTIME(temp_time, next_time);
6893 }
6894
6895 /* maintain all proxies in a consistent state. This should quickly become a task */
6896 time2 = maintain_proxies();
6897 return MINTIME(time2, next_time);
6898}
6899
6900
6901#if defined(ENABLE_EPOLL)
6902
6903/*
6904 * Main epoll() loop.
6905 */
6906
6907/* does 3 actions :
6908 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6909 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6910 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6911 *
6912 * returns 0 if initialization failed, !0 otherwise.
6913 */
6914
6915int epoll_loop(int action) {
6916 int next_time;
6917 int status;
6918 int fd;
6919
6920 int fds, count;
6921 int pr, pw, sr, sw;
6922 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
6923 struct epoll_event ev;
6924
6925 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01006926 static struct epoll_event *epoll_events = NULL;
6927 static int epoll_fd;
6928
6929 if (action == POLL_LOOP_ACTION_INIT) {
6930 epoll_fd = epoll_create(global.maxsock + 1);
6931 if (epoll_fd < 0)
6932 return 0;
6933 else {
6934 epoll_events = (struct epoll_event*)
6935 calloc(1, sizeof(struct epoll_event) * global.maxsock);
6936 PrevReadEvent = (fd_set *)
6937 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6938 PrevWriteEvent = (fd_set *)
6939 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006940 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006941 return 1;
6942 }
6943 else if (action == POLL_LOOP_ACTION_CLEAN) {
6944 if (PrevWriteEvent) free(PrevWriteEvent);
6945 if (PrevReadEvent) free(PrevReadEvent);
6946 if (epoll_events) free(epoll_events);
6947 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01006948 epoll_fd = 0;
6949 return 1;
6950 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006951
willy tarreau1c2ad212005-12-18 01:11:29 +01006952 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006953
willy tarreau1c2ad212005-12-18 01:11:29 +01006954 tv_now(&now);
6955
6956 while (1) {
6957 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01006958
6959 /* stop when there's no connection left and we don't allow them anymore */
6960 if (!actconn && listeners == 0)
6961 break;
6962
willy tarreau0f7af912005-12-17 12:21:26 +01006963#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01006964 {
6965 int time2;
6966 time2 = stats();
6967 next_time = MINTIME(time2, next_time);
6968 }
willy tarreau0f7af912005-12-17 12:21:26 +01006969#endif
6970
willy tarreau1c2ad212005-12-18 01:11:29 +01006971 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6972
6973 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
6974 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
6975
6976 if ((ro^rn) | (wo^wn)) {
6977 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6978#define FDSETS_ARE_INT_ALIGNED
6979#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01006980
willy tarreauad90a0c2005-12-18 01:09:15 +01006981#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6982#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01006983 pr = (ro >> count) & 1;
6984 pw = (wo >> count) & 1;
6985 sr = (rn >> count) & 1;
6986 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01006987#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006988 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
6989 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
6990 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6991 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01006992#endif
6993#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006994 pr = FD_ISSET(fd, PrevReadEvent);
6995 pw = FD_ISSET(fd, PrevWriteEvent);
6996 sr = FD_ISSET(fd, StaticReadEvent);
6997 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01006998#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01006999 if (!((sr^pr) | (sw^pw)))
7000 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01007001
willy tarreau1c2ad212005-12-18 01:11:29 +01007002 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
7003 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01007004
willy tarreaub952e1d2005-12-18 01:31:20 +01007005#ifdef EPOLL_CTL_MOD_WORKAROUND
7006 /* I encountered a rarely reproducible problem with
7007 * EPOLL_CTL_MOD where a modified FD (systematically
7008 * the one in epoll_events[0], fd#7) would sometimes
7009 * be set EPOLL_OUT while asked for a read ! This is
7010 * with the 2.4 epoll patch. The workaround is to
7011 * delete then recreate in case of modification.
7012 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
7013 * nor RHEL kernels.
7014 */
7015
7016 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
7017 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
7018
7019 if ((sr | sw))
7020 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
7021#else
willy tarreau1c2ad212005-12-18 01:11:29 +01007022 if ((pr | pw)) {
7023 /* the file-descriptor already exists... */
7024 if ((sr | sw)) {
7025 /* ...and it will still exist */
7026 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
7027 // perror("epoll_ctl(MOD)");
7028 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01007029 }
7030 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01007031 /* ...and it will be removed */
7032 if (fdtab[fd].state != FD_STCLOSE &&
7033 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
7034 // perror("epoll_ctl(DEL)");
7035 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01007036 }
7037 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007038 } else {
7039 /* the file-descriptor did not exist, let's add it */
7040 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
7041 // perror("epoll_ctl(ADD)");
7042 // exit(1);
7043 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007044 }
willy tarreaub952e1d2005-12-18 01:31:20 +01007045#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01007046 }
7047 ((int*)PrevReadEvent)[fds] = rn;
7048 ((int*)PrevWriteEvent)[fds] = wn;
7049 }
7050 }
7051
7052 /* now let's wait for events */
7053 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
7054 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01007055
willy tarreau1c2ad212005-12-18 01:11:29 +01007056 for (count = 0; count < status; count++) {
7057 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01007058
7059 if (FD_ISSET(fd, StaticReadEvent)) {
7060 if (fdtab[fd].state == FD_STCLOSE)
7061 continue;
7062 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
7063 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007064 }
willy tarreau05be12b2006-03-19 19:35:00 +01007065
7066 if (FD_ISSET(fd, StaticWriteEvent)) {
7067 if (fdtab[fd].state == FD_STCLOSE)
7068 continue;
7069 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
7070 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007071 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007072 }
7073 }
7074 return 1;
7075}
7076#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01007077
willy tarreauad90a0c2005-12-18 01:09:15 +01007078
willy tarreau5cbea6f2005-12-17 12:48:26 +01007079
willy tarreau1c2ad212005-12-18 01:11:29 +01007080#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01007081
willy tarreau1c2ad212005-12-18 01:11:29 +01007082/*
7083 * Main poll() loop.
7084 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007085
willy tarreau1c2ad212005-12-18 01:11:29 +01007086/* does 3 actions :
7087 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
7088 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
7089 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
7090 *
7091 * returns 0 if initialization failed, !0 otherwise.
7092 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007093
willy tarreau1c2ad212005-12-18 01:11:29 +01007094int poll_loop(int action) {
7095 int next_time;
7096 int status;
7097 int fd, nbfd;
7098
7099 int fds, count;
7100 int sr, sw;
7101 unsigned rn, wn; /* read new, write new */
7102
7103 /* private data */
7104 static struct pollfd *poll_events = NULL;
7105
7106 if (action == POLL_LOOP_ACTION_INIT) {
7107 poll_events = (struct pollfd*)
7108 calloc(1, sizeof(struct pollfd) * global.maxsock);
7109 return 1;
7110 }
7111 else if (action == POLL_LOOP_ACTION_CLEAN) {
7112 if (poll_events)
7113 free(poll_events);
7114 return 1;
7115 }
7116
7117 /* OK, it's POLL_LOOP_ACTION_RUN */
7118
7119 tv_now(&now);
7120
7121 while (1) {
7122 next_time = process_runnable_tasks();
7123
7124 /* stop when there's no connection left and we don't allow them anymore */
7125 if (!actconn && listeners == 0)
7126 break;
7127
7128#if STATTIME > 0
7129 {
7130 int time2;
7131 time2 = stats();
7132 next_time = MINTIME(time2, next_time);
7133 }
7134#endif
7135
7136
7137 nbfd = 0;
7138 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
7139
7140 rn = ((int*)StaticReadEvent)[fds];
7141 wn = ((int*)StaticWriteEvent)[fds];
7142
7143 if ((rn|wn)) {
7144 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
7145#define FDSETS_ARE_INT_ALIGNED
7146#ifdef FDSETS_ARE_INT_ALIGNED
7147
7148#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
7149#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
7150 sr = (rn >> count) & 1;
7151 sw = (wn >> count) & 1;
7152#else
7153 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
7154 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
7155#endif
7156#else
7157 sr = FD_ISSET(fd, StaticReadEvent);
7158 sw = FD_ISSET(fd, StaticWriteEvent);
7159#endif
7160 if ((sr|sw)) {
7161 poll_events[nbfd].fd = fd;
7162 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
7163 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01007164 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007165 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007166 }
7167 }
7168
7169 /* now let's wait for events */
7170 status = poll(poll_events, nbfd, next_time);
7171 tv_now(&now);
7172
7173 for (count = 0; status > 0 && count < nbfd; count++) {
7174 fd = poll_events[count].fd;
7175
willy tarreau606788e2006-05-21 16:26:20 +02007176 if (!(poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP )))
willy tarreau1c2ad212005-12-18 01:11:29 +01007177 continue;
7178
7179 /* ok, we found one active fd */
7180 status--;
7181
willy tarreau05be12b2006-03-19 19:35:00 +01007182 if (FD_ISSET(fd, StaticReadEvent)) {
7183 if (fdtab[fd].state == FD_STCLOSE)
7184 continue;
7185 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
7186 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007187 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007188
willy tarreau05be12b2006-03-19 19:35:00 +01007189 if (FD_ISSET(fd, StaticWriteEvent)) {
7190 if (fdtab[fd].state == FD_STCLOSE)
7191 continue;
7192 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
7193 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007194 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007195 }
7196 }
7197 return 1;
7198}
willy tarreauad90a0c2005-12-18 01:09:15 +01007199#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01007200
willy tarreauad90a0c2005-12-18 01:09:15 +01007201
willy tarreauad90a0c2005-12-18 01:09:15 +01007202
willy tarreau1c2ad212005-12-18 01:11:29 +01007203/*
7204 * Main select() loop.
7205 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007206
willy tarreau1c2ad212005-12-18 01:11:29 +01007207/* does 3 actions :
7208 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
7209 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
7210 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
7211 *
7212 * returns 0 if initialization failed, !0 otherwise.
7213 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007214
willy tarreauad90a0c2005-12-18 01:09:15 +01007215
willy tarreau1c2ad212005-12-18 01:11:29 +01007216int select_loop(int action) {
7217 int next_time;
7218 int status;
7219 int fd,i;
7220 struct timeval delta;
7221 int readnotnull, writenotnull;
7222 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01007223
willy tarreau1c2ad212005-12-18 01:11:29 +01007224 if (action == POLL_LOOP_ACTION_INIT) {
7225 ReadEvent = (fd_set *)
7226 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
7227 WriteEvent = (fd_set *)
7228 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
7229 return 1;
7230 }
7231 else if (action == POLL_LOOP_ACTION_CLEAN) {
7232 if (WriteEvent) free(WriteEvent);
7233 if (ReadEvent) free(ReadEvent);
7234 return 1;
7235 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007236
willy tarreau1c2ad212005-12-18 01:11:29 +01007237 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01007238
willy tarreau1c2ad212005-12-18 01:11:29 +01007239 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01007240
willy tarreau1c2ad212005-12-18 01:11:29 +01007241 while (1) {
7242 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01007243
willy tarreau1c2ad212005-12-18 01:11:29 +01007244 /* stop when there's no connection left and we don't allow them anymore */
7245 if (!actconn && listeners == 0)
7246 break;
7247
7248#if STATTIME > 0
7249 {
7250 int time2;
7251 time2 = stats();
7252 next_time = MINTIME(time2, next_time);
7253 }
7254#endif
7255
willy tarreau1c2ad212005-12-18 01:11:29 +01007256 if (next_time > 0) { /* FIXME */
7257 /* Convert to timeval */
7258 /* to avoid eventual select loops due to timer precision */
7259 next_time += SCHEDULER_RESOLUTION;
7260 delta.tv_sec = next_time / 1000;
7261 delta.tv_usec = (next_time % 1000) * 1000;
7262 }
7263 else if (next_time == 0) { /* allow select to return immediately when needed */
7264 delta.tv_sec = delta.tv_usec = 0;
7265 }
7266
7267
7268 /* let's restore fdset state */
7269
7270 readnotnull = 0; writenotnull = 0;
7271 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
7272 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
7273 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
7274 }
7275
7276 // /* just a verification code, needs to be removed for performance */
7277 // for (i=0; i<maxfd; i++) {
7278 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
7279 // abort();
7280 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
7281 // abort();
7282 //
7283 // }
7284
7285 status = select(maxfd,
7286 readnotnull ? ReadEvent : NULL,
7287 writenotnull ? WriteEvent : NULL,
7288 NULL,
7289 (next_time >= 0) ? &delta : NULL);
7290
7291 /* this is an experiment on the separation of the select work */
7292 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
7293 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
7294
7295 tv_now(&now);
7296
7297 if (status > 0) { /* must proceed with events */
7298
7299 int fds;
7300 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01007301
willy tarreau1c2ad212005-12-18 01:11:29 +01007302 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
7303 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
7304 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
7305
7306 /* if we specify read first, the accepts and zero reads will be
7307 * seen first. Moreover, system buffers will be flushed faster.
7308 */
willy tarreau05be12b2006-03-19 19:35:00 +01007309 if (FD_ISSET(fd, ReadEvent)) {
7310 if (fdtab[fd].state == FD_STCLOSE)
7311 continue;
7312 fdtab[fd].read(fd);
7313 }
willy tarreau64a3cc32005-12-18 01:13:11 +01007314
willy tarreau05be12b2006-03-19 19:35:00 +01007315 if (FD_ISSET(fd, WriteEvent)) {
7316 if (fdtab[fd].state == FD_STCLOSE)
7317 continue;
7318 fdtab[fd].write(fd);
7319 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007320 }
7321 }
7322 else {
7323 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01007324 }
willy tarreau0f7af912005-12-17 12:21:26 +01007325 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007326 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01007327}
7328
7329
7330#if STATTIME > 0
7331/*
7332 * Display proxy statistics regularly. It is designed to be called from the
7333 * select_loop().
7334 */
7335int stats(void) {
7336 static int lines;
7337 static struct timeval nextevt;
7338 static struct timeval lastevt;
7339 static struct timeval starttime = {0,0};
7340 unsigned long totaltime, deltatime;
7341 int ret;
7342
willy tarreau750a4722005-12-17 13:21:24 +01007343 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01007344 deltatime = (tv_diff(&lastevt, &now)?:1);
7345 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01007346
willy tarreau9fe663a2005-12-17 13:02:59 +01007347 if (global.mode & MODE_STATS) {
7348 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007349 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007350 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
7351 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007352 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01007353 actconn, totalconn,
7354 stats_tsk_new, stats_tsk_good,
7355 stats_tsk_left, stats_tsk_right,
7356 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
7357 }
7358 }
7359
7360 tv_delayfrom(&nextevt, &now, STATTIME);
7361
7362 lastevt=now;
7363 }
7364 ret = tv_remain(&now, &nextevt);
7365 return ret;
7366}
7367#endif
7368
7369
7370/*
7371 * this function enables proxies when there are enough free sessions,
7372 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01007373 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01007374 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01007375 */
7376static int maintain_proxies(void) {
7377 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01007378 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007379 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01007380
7381 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01007382 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01007383
7384 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01007385 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01007386 while (p) {
7387 if (p->nbconn < p->maxconn) {
7388 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007389 for (l = p->listen; l != NULL; l = l->next) {
7390 FD_SET(l->fd, StaticReadEvent);
7391 }
willy tarreau0f7af912005-12-17 12:21:26 +01007392 p->state = PR_STRUN;
7393 }
7394 }
7395 else {
7396 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007397 for (l = p->listen; l != NULL; l = l->next) {
7398 FD_CLR(l->fd, StaticReadEvent);
7399 }
willy tarreau0f7af912005-12-17 12:21:26 +01007400 p->state = PR_STIDLE;
7401 }
7402 }
7403 p = p->next;
7404 }
7405 }
7406 else { /* block all proxies */
7407 while (p) {
7408 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007409 for (l = p->listen; l != NULL; l = l->next) {
7410 FD_CLR(l->fd, StaticReadEvent);
7411 }
willy tarreau0f7af912005-12-17 12:21:26 +01007412 p->state = PR_STIDLE;
7413 }
7414 p = p->next;
7415 }
7416 }
7417
willy tarreau5cbea6f2005-12-17 12:48:26 +01007418 if (stopping) {
7419 p = proxy;
7420 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007421 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007422 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01007423 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007424 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01007425 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01007426 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01007427
willy tarreaua41a8b42005-12-17 14:02:24 +01007428 for (l = p->listen; l != NULL; l = l->next) {
7429 fd_delete(l->fd);
7430 listeners--;
7431 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007432 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007433 }
7434 else {
7435 tleft = MINTIME(t, tleft);
7436 }
7437 }
7438 p = p->next;
7439 }
7440 }
7441 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01007442}
7443
7444/*
7445 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01007446 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
7447 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01007448 */
7449static void soft_stop(void) {
7450 struct proxy *p;
7451
7452 stopping = 1;
7453 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007454 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01007455 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01007456 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01007457 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01007458 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01007459 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01007460 }
willy tarreau0f7af912005-12-17 12:21:26 +01007461 p = p->next;
7462 }
7463}
7464
willy tarreaufac1a862006-05-21 10:20:28 +02007465/*
7466 * Linux unbinds the listen socket after a SHUT_RD, and ignores SHUT_WR.
7467 * Solaris refuses either shutdown().
7468 * OpenBSD ignores SHUT_RD but closes upon SHUT_WR and refuses to rebind.
7469 * So a common validation path involves SHUT_WR && listen && SHUT_RD.
7470 * If disabling at least one listener returns an error, then the proxy
7471 * state is set to PR_STERROR because we don't know how to resume from this.
7472 */
willy tarreaudbd3bef2006-01-20 19:35:18 +01007473static void pause_proxy(struct proxy *p) {
7474 struct listener *l;
7475 for (l = p->listen; l != NULL; l = l->next) {
willy tarreaufac1a862006-05-21 10:20:28 +02007476 if (shutdown(l->fd, SHUT_WR) == 0 && listen(l->fd, p->maxconn) == 0 &&
7477 shutdown(l->fd, SHUT_RD) == 0) {
Willy TARREAU007aa462006-05-14 09:55:23 +02007478 FD_CLR(l->fd, StaticReadEvent);
willy tarreaufac1a862006-05-21 10:20:28 +02007479 if (p->state != PR_STERROR)
7480 p->state = PR_STPAUSED;
Willy TARREAU007aa462006-05-14 09:55:23 +02007481 }
willy tarreaufac1a862006-05-21 10:20:28 +02007482 else
7483 p->state = PR_STERROR;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007484 }
7485}
7486
7487/*
7488 * This function temporarily disables listening so that another new instance
7489 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01007490 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01007491 * the proxy, or a SIGTTIN can be sent to listen again.
7492 */
7493static void pause_proxies(void) {
Willy TARREAU007aa462006-05-14 09:55:23 +02007494 int err;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007495 struct proxy *p;
7496
Willy TARREAU007aa462006-05-14 09:55:23 +02007497 err = 0;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007498 p = proxy;
7499 tv_now(&now); /* else, the old time before select will be used */
7500 while (p) {
willy tarreaufac1a862006-05-21 10:20:28 +02007501 if (p->state != PR_STERROR && p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007502 Warning("Pausing proxy %s.\n", p->id);
7503 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
7504 pause_proxy(p);
Willy TARREAU007aa462006-05-14 09:55:23 +02007505 if (p->state != PR_STPAUSED) {
7506 err |= 1;
7507 Warning("Proxy %s failed to enter pause mode.\n", p->id);
7508 send_log(p, LOG_WARNING, "Proxy %s failed to enter pause mode.\n", p->id);
7509 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007510 }
7511 p = p->next;
7512 }
Willy TARREAU007aa462006-05-14 09:55:23 +02007513 if (err) {
7514 Warning("Some proxies refused to pause, performing soft stop now.\n");
7515 send_log(p, LOG_WARNING, "Some proxies refused to pause, performing soft stop now.\n");
7516 soft_stop();
7517 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007518}
7519
7520
7521/*
7522 * This function reactivates listening. This can be used after a call to
7523 * sig_pause(), for example when a new instance has failed starting up.
7524 * It is designed to be called upon reception of a SIGTTIN.
7525 */
7526static void listen_proxies(void) {
7527 struct proxy *p;
7528 struct listener *l;
7529
7530 p = proxy;
7531 tv_now(&now); /* else, the old time before select will be used */
7532 while (p) {
7533 if (p->state == PR_STPAUSED) {
7534 Warning("Enabling proxy %s.\n", p->id);
7535 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
7536
7537 for (l = p->listen; l != NULL; l = l->next) {
7538 if (listen(l->fd, p->maxconn) == 0) {
7539 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
7540 FD_SET(l->fd, StaticReadEvent);
7541 p->state = PR_STRUN;
7542 }
7543 else
7544 p->state = PR_STIDLE;
7545 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01007546 int port;
7547
7548 if (l->addr.ss_family == AF_INET6)
7549 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
7550 else
7551 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
7552
willy tarreaudbd3bef2006-01-20 19:35:18 +01007553 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01007554 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01007555 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01007556 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01007557 /* Another port might have been enabled. Let's stop everything. */
7558 pause_proxy(p);
7559 break;
7560 }
7561 }
7562 }
7563 p = p->next;
7564 }
7565}
7566
7567
willy tarreau0f7af912005-12-17 12:21:26 +01007568/*
7569 * upon SIGUSR1, let's have a soft stop.
7570 */
7571void sig_soft_stop(int sig) {
7572 soft_stop();
7573 signal(sig, SIG_IGN);
7574}
7575
willy tarreaudbd3bef2006-01-20 19:35:18 +01007576/*
7577 * upon SIGTTOU, we pause everything
7578 */
7579void sig_pause(int sig) {
7580 pause_proxies();
7581 signal(sig, sig_pause);
7582}
willy tarreau0f7af912005-12-17 12:21:26 +01007583
willy tarreau8337c6b2005-12-17 13:41:01 +01007584/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01007585 * upon SIGTTIN, let's have a soft stop.
7586 */
7587void sig_listen(int sig) {
7588 listen_proxies();
7589 signal(sig, sig_listen);
7590}
7591
7592/*
willy tarreau8337c6b2005-12-17 13:41:01 +01007593 * this function dumps every server's state when the process receives SIGHUP.
7594 */
7595void sig_dump_state(int sig) {
7596 struct proxy *p = proxy;
7597
7598 Warning("SIGHUP received, dumping servers states.\n");
7599 while (p) {
7600 struct server *s = p->srv;
7601
willy tarreau4632c212006-05-02 23:32:51 +02007602 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01007603 while (s) {
willy tarreau4632c212006-05-02 23:32:51 +02007604 snprintf(trash, sizeof(trash),
7605 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %d tot.",
7606 p->id, s->id,
7607 (s->state & SRV_RUNNING) ? "UP" : "DOWN",
7608 s->cur_sess, s->nbpend, s->cum_sess);
willy tarreau14b4d432006-04-07 18:23:29 +02007609 Warning("%s\n", trash);
7610 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01007611 s = s->next;
7612 }
willy tarreaudd07e972005-12-18 00:48:48 +01007613
willy tarreau62084d42006-03-24 18:57:41 +01007614 if (p->srv_act == 0) {
willy tarreau4632c212006-05-02 23:32:51 +02007615 snprintf(trash, sizeof(trash),
7616 "SIGHUP: Proxy %s %s ! Conn: %d act, %d pend (%d unass), %d tot.",
7617 p->id,
7618 (p->srv_bck) ? "is running on backup servers" : "has no server available",
7619 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02007620 } else {
7621 snprintf(trash, sizeof(trash),
willy tarreau4632c212006-05-02 23:32:51 +02007622 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
7623 " Conn: %d act, %d pend (%d unass), %d tot.",
7624 p->id, p->srv_act, p->srv_bck,
7625 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02007626 }
7627 Warning("%s\n", trash);
7628 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01007629
willy tarreau8337c6b2005-12-17 13:41:01 +01007630 p = p->next;
7631 }
7632 signal(sig, sig_dump_state);
7633}
7634
willy tarreau0f7af912005-12-17 12:21:26 +01007635void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007636 struct task *t, *tnext;
7637 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01007638
willy tarreau5e698ef2006-05-02 14:51:00 +02007639 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
7640 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007641 tnext = t->next;
7642 s = t->context;
7643 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
7644 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
7645 "req=%d, rep=%d, clifd=%d\n",
7646 s, tv_remain(&now, &t->expire),
7647 s->cli_state,
7648 s->srv_state,
7649 FD_ISSET(s->cli_fd, StaticReadEvent),
7650 FD_ISSET(s->cli_fd, StaticWriteEvent),
7651 FD_ISSET(s->srv_fd, StaticReadEvent),
7652 FD_ISSET(s->srv_fd, StaticWriteEvent),
7653 s->req->l, s->rep?s->rep->l:0, s->cli_fd
7654 );
willy tarreau0f7af912005-12-17 12:21:26 +01007655 }
willy tarreau12350152005-12-18 01:03:27 +01007656}
7657
willy tarreau64a3cc32005-12-18 01:13:11 +01007658#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01007659static void fast_stop(void)
7660{
7661 struct proxy *p;
7662 p = proxy;
7663 while (p) {
7664 p->grace = 0;
7665 p = p->next;
7666 }
7667 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01007668}
7669
willy tarreau12350152005-12-18 01:03:27 +01007670void sig_int(int sig) {
7671 /* This would normally be a hard stop,
7672 but we want to be sure about deallocation,
7673 and so on, so we do a soft stop with
7674 0 GRACE time
7675 */
7676 fast_stop();
7677 /* If we are killed twice, we decide to die*/
7678 signal(sig, SIG_DFL);
7679}
7680
7681void sig_term(int sig) {
7682 /* This would normally be a hard stop,
7683 but we want to be sure about deallocation,
7684 and so on, so we do a soft stop with
7685 0 GRACE time
7686 */
7687 fast_stop();
7688 /* If we are killed twice, we decide to die*/
7689 signal(sig, SIG_DFL);
7690}
willy tarreau64a3cc32005-12-18 01:13:11 +01007691#endif
willy tarreau12350152005-12-18 01:03:27 +01007692
willy tarreauc1f47532005-12-18 01:08:26 +01007693/* returns the pointer to an error in the replacement string, or NULL if OK */
7694char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01007695 struct hdr_exp *exp;
7696
willy tarreauc1f47532005-12-18 01:08:26 +01007697 if (replace != NULL) {
7698 char *err;
7699 err = check_replace_string(replace);
7700 if (err)
7701 return err;
7702 }
7703
willy tarreaue39cd132005-12-17 13:00:18 +01007704 while (*head != NULL)
7705 head = &(*head)->next;
7706
7707 exp = calloc(1, sizeof(struct hdr_exp));
7708
7709 exp->preg = preg;
7710 exp->replace = replace;
7711 exp->action = action;
7712 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01007713
7714 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007715}
7716
willy tarreau9fe663a2005-12-17 13:02:59 +01007717
willy tarreau0f7af912005-12-17 12:21:26 +01007718/*
willy tarreau9fe663a2005-12-17 13:02:59 +01007719 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01007720 */
willy tarreau9fe663a2005-12-17 13:02:59 +01007721int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01007722
willy tarreau9fe663a2005-12-17 13:02:59 +01007723 if (!strcmp(args[0], "global")) { /* new section */
7724 /* no option, nothing special to do */
7725 return 0;
7726 }
7727 else if (!strcmp(args[0], "daemon")) {
7728 global.mode |= MODE_DAEMON;
7729 }
7730 else if (!strcmp(args[0], "debug")) {
7731 global.mode |= MODE_DEBUG;
7732 }
willy tarreau64a3cc32005-12-18 01:13:11 +01007733 else if (!strcmp(args[0], "noepoll")) {
7734 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
7735 }
7736 else if (!strcmp(args[0], "nopoll")) {
7737 cfg_polling_mechanism &= ~POLL_USE_POLL;
7738 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007739 else if (!strcmp(args[0], "quiet")) {
7740 global.mode |= MODE_QUIET;
7741 }
7742 else if (!strcmp(args[0], "stats")) {
7743 global.mode |= MODE_STATS;
7744 }
7745 else if (!strcmp(args[0], "uid")) {
7746 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007747 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007748 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007749 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007750 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007751 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007752 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007753 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007754 global.uid = atol(args[1]);
7755 }
7756 else if (!strcmp(args[0], "gid")) {
7757 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007758 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007759 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007760 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007761 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007762 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007763 return -1;
7764 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007765 global.gid = atol(args[1]);
7766 }
7767 else if (!strcmp(args[0], "nbproc")) {
7768 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007769 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007770 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007771 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007772 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007773 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007774 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007775 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007776 global.nbproc = atol(args[1]);
7777 }
7778 else if (!strcmp(args[0], "maxconn")) {
7779 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007780 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007781 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007782 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007783 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007784 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007785 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007786 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007787 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01007788#ifdef SYSTEM_MAXCONN
7789 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
7790 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);
7791 global.maxconn = DEFAULT_MAXCONN;
7792 }
7793#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01007794 }
willy tarreaub1285d52005-12-18 01:20:14 +01007795 else if (!strcmp(args[0], "ulimit-n")) {
7796 if (global.rlimit_nofile != 0) {
7797 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7798 return 0;
7799 }
7800 if (*(args[1]) == 0) {
7801 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
7802 return -1;
7803 }
7804 global.rlimit_nofile = atol(args[1]);
7805 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007806 else if (!strcmp(args[0], "chroot")) {
7807 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007808 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007809 return 0;
7810 }
7811 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007812 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007813 return -1;
7814 }
7815 global.chroot = strdup(args[1]);
7816 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007817 else if (!strcmp(args[0], "pidfile")) {
7818 if (global.pidfile != NULL) {
7819 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7820 return 0;
7821 }
7822 if (*(args[1]) == 0) {
7823 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
7824 return -1;
7825 }
7826 global.pidfile = strdup(args[1]);
7827 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007828 else if (!strcmp(args[0], "log")) { /* syslog server address */
7829 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01007830 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007831
7832 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007833 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007834 return -1;
7835 }
7836
7837 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7838 if (!strcmp(log_facilities[facility], args[2]))
7839 break;
7840
7841 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007842 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007843 exit(1);
7844 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007845
7846 level = 7; /* max syslog level = debug */
7847 if (*(args[3])) {
7848 while (level >= 0 && strcmp(log_levels[level], args[3]))
7849 level--;
7850 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007851 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007852 exit(1);
7853 }
7854 }
7855
willy tarreau9fe663a2005-12-17 13:02:59 +01007856 sa = str2sa(args[1]);
7857 if (!sa->sin_port)
7858 sa->sin_port = htons(SYSLOG_PORT);
7859
7860 if (global.logfac1 == -1) {
7861 global.logsrv1 = *sa;
7862 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007863 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007864 }
7865 else if (global.logfac2 == -1) {
7866 global.logsrv2 = *sa;
7867 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007868 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007869 }
7870 else {
7871 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
7872 return -1;
7873 }
7874
7875 }
7876 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007877 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01007878 return -1;
7879 }
7880 return 0;
7881}
7882
7883
willy tarreaua41a8b42005-12-17 14:02:24 +01007884void init_default_instance() {
7885 memset(&defproxy, 0, sizeof(defproxy));
7886 defproxy.mode = PR_MODE_TCP;
7887 defproxy.state = PR_STNEW;
7888 defproxy.maxconn = cfg_maxpconn;
7889 defproxy.conn_retries = CONN_RETRIES;
7890 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
7891}
7892
willy tarreau9fe663a2005-12-17 13:02:59 +01007893/*
7894 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
7895 */
7896int cfg_parse_listen(char *file, int linenum, char **args) {
7897 static struct proxy *curproxy = NULL;
7898 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01007899 char *err;
willy tarreau12350152005-12-18 01:03:27 +01007900 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01007901
7902 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01007903 if (!*args[1]) {
7904 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
7905 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007906 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007907 return -1;
7908 }
7909
7910 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007911 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007912 return -1;
7913 }
willy tarreaudfece232006-05-02 00:19:57 +02007914
willy tarreau9fe663a2005-12-17 13:02:59 +01007915 curproxy->next = proxy;
7916 proxy = curproxy;
willy tarreaudfece232006-05-02 00:19:57 +02007917 LIST_INIT(&curproxy->pendconns);
7918
willy tarreau9fe663a2005-12-17 13:02:59 +01007919 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01007920
7921 /* parse the listener address if any */
7922 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007923 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007924 if (!curproxy->listen)
7925 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007926 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01007927 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007928
willy tarreau9fe663a2005-12-17 13:02:59 +01007929 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01007930 curproxy->state = defproxy.state;
7931 curproxy->maxconn = defproxy.maxconn;
7932 curproxy->conn_retries = defproxy.conn_retries;
7933 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007934
7935 if (defproxy.check_req)
7936 curproxy->check_req = strdup(defproxy.check_req);
7937 curproxy->check_len = defproxy.check_len;
7938
7939 if (defproxy.cookie_name)
7940 curproxy->cookie_name = strdup(defproxy.cookie_name);
7941 curproxy->cookie_len = defproxy.cookie_len;
7942
7943 if (defproxy.capture_name)
7944 curproxy->capture_name = strdup(defproxy.capture_name);
7945 curproxy->capture_namelen = defproxy.capture_namelen;
7946 curproxy->capture_len = defproxy.capture_len;
7947
7948 if (defproxy.errmsg.msg400)
7949 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
7950 curproxy->errmsg.len400 = defproxy.errmsg.len400;
7951
7952 if (defproxy.errmsg.msg403)
7953 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
7954 curproxy->errmsg.len403 = defproxy.errmsg.len403;
7955
7956 if (defproxy.errmsg.msg408)
7957 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
7958 curproxy->errmsg.len408 = defproxy.errmsg.len408;
7959
7960 if (defproxy.errmsg.msg500)
7961 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
7962 curproxy->errmsg.len500 = defproxy.errmsg.len500;
7963
7964 if (defproxy.errmsg.msg502)
7965 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
7966 curproxy->errmsg.len502 = defproxy.errmsg.len502;
7967
7968 if (defproxy.errmsg.msg503)
7969 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
7970 curproxy->errmsg.len503 = defproxy.errmsg.len503;
7971
7972 if (defproxy.errmsg.msg504)
7973 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
7974 curproxy->errmsg.len504 = defproxy.errmsg.len504;
7975
willy tarreaua41a8b42005-12-17 14:02:24 +01007976 curproxy->clitimeout = defproxy.clitimeout;
7977 curproxy->contimeout = defproxy.contimeout;
7978 curproxy->srvtimeout = defproxy.srvtimeout;
7979 curproxy->mode = defproxy.mode;
7980 curproxy->logfac1 = defproxy.logfac1;
7981 curproxy->logsrv1 = defproxy.logsrv1;
7982 curproxy->loglev1 = defproxy.loglev1;
7983 curproxy->logfac2 = defproxy.logfac2;
7984 curproxy->logsrv2 = defproxy.logsrv2;
7985 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01007986 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01007987 curproxy->grace = defproxy.grace;
willy tarreau1f431b52006-05-21 14:46:15 +02007988 curproxy->uri_auth = defproxy.uri_auth;
willy tarreaua41a8b42005-12-17 14:02:24 +01007989 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01007990 curproxy->mon_net = defproxy.mon_net;
7991 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01007992 return 0;
7993 }
7994 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007995 /* some variables may have already been initialized earlier */
7996 if (defproxy.check_req) free(defproxy.check_req);
7997 if (defproxy.cookie_name) free(defproxy.cookie_name);
7998 if (defproxy.capture_name) free(defproxy.capture_name);
7999 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
8000 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
8001 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
8002 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
8003 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
8004 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
8005 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
willy tarreau1f431b52006-05-21 14:46:15 +02008006 /* we cannot free uri_auth because it might already be used */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008007 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01008008 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01008009 return 0;
8010 }
8011 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008012 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01008013 return -1;
8014 }
8015
willy tarreaua41a8b42005-12-17 14:02:24 +01008016 if (!strcmp(args[0], "bind")) { /* new listen addresses */
8017 if (curproxy == &defproxy) {
8018 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8019 return -1;
8020 }
8021
8022 if (strchr(args[1], ':') == NULL) {
8023 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
8024 file, linenum, args[0]);
8025 return -1;
8026 }
8027 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01008028 if (!curproxy->listen)
8029 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008030 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01008031 return 0;
8032 }
willy tarreaub1285d52005-12-18 01:20:14 +01008033 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
8034 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
8035 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
8036 file, linenum, args[0]);
8037 return -1;
8038 }
8039 /* flush useless bits */
8040 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
8041 return 0;
8042 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008043 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01008044 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
8045 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
8046 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
8047 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008048 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008049 return -1;
8050 }
8051 }
8052 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01008053 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01008054 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008055 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
8056 curproxy->state = PR_STNEW;
8057 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008058 else if (!strcmp(args[0], "cookie")) { /* cookie name */
8059 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01008060// if (curproxy == &defproxy) {
8061// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8062// return -1;
8063// }
willy tarreaua41a8b42005-12-17 14:02:24 +01008064
willy tarreau9fe663a2005-12-17 13:02:59 +01008065 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008066// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
8067// file, linenum);
8068// return 0;
8069 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01008070 }
8071
8072 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008073 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
8074 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008075 return -1;
8076 }
8077 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008078 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01008079
8080 cur_arg = 2;
8081 while (*(args[cur_arg])) {
8082 if (!strcmp(args[cur_arg], "rewrite")) {
8083 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01008084 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008085 else if (!strcmp(args[cur_arg], "indirect")) {
8086 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01008087 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008088 else if (!strcmp(args[cur_arg], "insert")) {
8089 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01008090 }
willy tarreau240afa62005-12-17 13:14:35 +01008091 else if (!strcmp(args[cur_arg], "nocache")) {
8092 curproxy->options |= PR_O_COOK_NOC;
8093 }
willy tarreaucd878942005-12-17 13:27:43 +01008094 else if (!strcmp(args[cur_arg], "postonly")) {
8095 curproxy->options |= PR_O_COOK_POST;
8096 }
willy tarreau0174f312005-12-18 01:02:42 +01008097 else if (!strcmp(args[cur_arg], "prefix")) {
8098 curproxy->options |= PR_O_COOK_PFX;
8099 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008100 else {
willy tarreau0174f312005-12-18 01:02:42 +01008101 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008102 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01008103 return -1;
8104 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008105 cur_arg++;
8106 }
willy tarreau0174f312005-12-18 01:02:42 +01008107 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
8108 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
8109 file, linenum);
8110 return -1;
8111 }
8112
8113 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
8114 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01008115 file, linenum);
8116 return -1;
8117 }
willy tarreau12350152005-12-18 01:03:27 +01008118 }/* end else if (!strcmp(args[0], "cookie")) */
8119 else if (!strcmp(args[0], "appsession")) { /* cookie name */
8120// if (curproxy == &defproxy) {
8121// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8122// return -1;
8123// }
8124
8125 if (curproxy->appsession_name != NULL) {
8126// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
8127// file, linenum);
8128// return 0;
8129 free(curproxy->appsession_name);
8130 }
8131
8132 if (*(args[5]) == 0) {
8133 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
8134 file, linenum, args[0]);
8135 return -1;
8136 }
8137 have_appsession = 1;
8138 curproxy->appsession_name = strdup(args[1]);
8139 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
8140 curproxy->appsession_len = atoi(args[3]);
8141 curproxy->appsession_timeout = atoi(args[5]);
8142 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
8143 if (rc) {
8144 Alert("Error Init Appsession Hashtable.\n");
8145 return -1;
8146 }
8147 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01008148 else if (!strcmp(args[0], "capture")) {
8149 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
8150 // if (curproxy == &defproxy) {
8151 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8152 // return -1;
8153 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01008154
willy tarreau4302f492005-12-18 01:00:37 +01008155 if (curproxy->capture_name != NULL) {
8156 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
8157 // file, linenum, args[0]);
8158 // return 0;
8159 free(curproxy->capture_name);
8160 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008161
willy tarreau4302f492005-12-18 01:00:37 +01008162 if (*(args[4]) == 0) {
8163 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
8164 file, linenum, args[0]);
8165 return -1;
8166 }
8167 curproxy->capture_name = strdup(args[2]);
8168 curproxy->capture_namelen = strlen(curproxy->capture_name);
8169 curproxy->capture_len = atol(args[4]);
8170 if (curproxy->capture_len >= CAPTURE_LEN) {
8171 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
8172 file, linenum, CAPTURE_LEN - 1);
8173 curproxy->capture_len = CAPTURE_LEN - 1;
8174 }
8175 curproxy->to_log |= LW_COOKIE;
8176 }
8177 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
8178 struct cap_hdr *hdr;
8179
8180 if (curproxy == &defproxy) {
8181 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
8182 return -1;
8183 }
8184
8185 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
8186 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
8187 file, linenum, args[0], args[1]);
8188 return -1;
8189 }
8190
8191 hdr = calloc(sizeof(struct cap_hdr), 1);
8192 hdr->next = curproxy->req_cap;
8193 hdr->name = strdup(args[3]);
8194 hdr->namelen = strlen(args[3]);
8195 hdr->len = atol(args[5]);
8196 hdr->index = curproxy->nb_req_cap++;
8197 curproxy->req_cap = hdr;
8198 curproxy->to_log |= LW_REQHDR;
8199 }
8200 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
8201 struct cap_hdr *hdr;
8202
8203 if (curproxy == &defproxy) {
8204 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
8205 return -1;
8206 }
8207
8208 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
8209 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
8210 file, linenum, args[0], args[1]);
8211 return -1;
8212 }
8213 hdr = calloc(sizeof(struct cap_hdr), 1);
8214 hdr->next = curproxy->rsp_cap;
8215 hdr->name = strdup(args[3]);
8216 hdr->namelen = strlen(args[3]);
8217 hdr->len = atol(args[5]);
8218 hdr->index = curproxy->nb_rsp_cap++;
8219 curproxy->rsp_cap = hdr;
8220 curproxy->to_log |= LW_RSPHDR;
8221 }
8222 else {
8223 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008224 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008225 return -1;
8226 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008227 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008228 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008229 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008230 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008231 return 0;
8232 }
8233 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008234 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8235 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008236 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008237 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008238 curproxy->contimeout = atol(args[1]);
8239 }
8240 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008241 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008242 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
8243 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008244 return 0;
8245 }
8246 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008247 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8248 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008249 return -1;
8250 }
8251 curproxy->clitimeout = atol(args[1]);
8252 }
8253 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008254 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008255 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008256 return 0;
8257 }
8258 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008259 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8260 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01008261 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008262 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008263 curproxy->srvtimeout = atol(args[1]);
8264 }
8265 else if (!strcmp(args[0], "retries")) { /* connection retries */
8266 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008267 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
8268 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008269 return -1;
8270 }
8271 curproxy->conn_retries = atol(args[1]);
8272 }
willy tarreau9e138862006-05-14 23:06:28 +02008273 else if (!strcmp(args[0], "stats")) {
willy tarreau1f431b52006-05-21 14:46:15 +02008274 if (curproxy != &defproxy && curproxy->uri_auth == defproxy.uri_auth)
8275 curproxy->uri_auth = NULL; /* we must detach from the default config */
8276
willy tarreau9e138862006-05-14 23:06:28 +02008277 if (*(args[1]) == 0) {
willy tarreau1f431b52006-05-21 14:46:15 +02008278 Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'auth', 'scope' or 'enable'.\n", file, linenum, args[0]);
willy tarreau9e138862006-05-14 23:06:28 +02008279 return -1;
8280 } else if (!strcmp(args[1], "uri")) {
8281 if (*(args[2]) == 0) {
8282 Alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
8283 return -1;
8284 } else if (!stats_set_uri(&curproxy->uri_auth, args[2])) {
8285 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8286 return -1;
8287 }
8288 } else if (!strcmp(args[1], "realm")) {
8289 if (*(args[2]) == 0) {
8290 Alert("parsing [%s:%d] : 'realm' needs an realm name.\n", file, linenum);
8291 return -1;
8292 } else if (!stats_set_realm(&curproxy->uri_auth, args[2])) {
8293 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8294 return -1;
8295 }
8296 } else if (!strcmp(args[1], "auth")) {
8297 if (*(args[2]) == 0) {
8298 Alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
8299 return -1;
8300 } else if (!stats_add_auth(&curproxy->uri_auth, args[2])) {
8301 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8302 return -1;
8303 }
willy tarreau1f431b52006-05-21 14:46:15 +02008304 } else if (!strcmp(args[1], "scope")) {
8305 if (*(args[2]) == 0) {
8306 Alert("parsing [%s:%d] : 'scope' needs a proxy name.\n", file, linenum);
8307 return -1;
8308 } else if (!stats_add_scope(&curproxy->uri_auth, args[2])) {
8309 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8310 return -1;
8311 }
willy tarreau9e138862006-05-14 23:06:28 +02008312 } else if (!strcmp(args[1], "enable")) {
8313 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
8314 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8315 return -1;
8316 }
8317 } else {
8318 Alert("parsing [%s:%d] : unknown stats parameter '%s' (expects 'uri', 'realm', 'auth' or 'enable').\n",
8319 file, linenum, args[0]);
8320 return -1;
8321 }
8322 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008323 else if (!strcmp(args[0], "option")) {
8324 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008325 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008326 return -1;
8327 }
8328 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01008329 /* enable reconnections to dispatch */
8330 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01008331#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01008332 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01008333 /* enable transparent proxy connections */
8334 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01008335#endif
8336 else if (!strcmp(args[1], "keepalive"))
8337 /* enable keep-alive */
8338 curproxy->options |= PR_O_KEEPALIVE;
8339 else if (!strcmp(args[1], "forwardfor"))
8340 /* insert x-forwarded-for field */
8341 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01008342 else if (!strcmp(args[1], "logasap"))
8343 /* log as soon as possible, without waiting for the session to complete */
8344 curproxy->options |= PR_O_LOGASAP;
willy tarreau03a92de2006-05-21 18:26:53 +02008345 else if (!strcmp(args[1], "abortonclose"))
8346 /* abort connection if client closes during queue or connect() */
8347 curproxy->options |= PR_O_ABRT_CLOSE;
willy tarreau25c4ea52005-12-18 00:49:49 +01008348 else if (!strcmp(args[1], "httpclose"))
8349 /* force connection: close in both directions in HTTP mode */
8350 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01008351 else if (!strcmp(args[1], "forceclose"))
8352 /* force connection: close in both directions in HTTP mode and enforce end of session */
8353 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01008354 else if (!strcmp(args[1], "checkcache"))
8355 /* require examination of cacheability of the 'set-cookie' field */
8356 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01008357 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01008358 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01008359 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01008360 else if (!strcmp(args[1], "tcplog"))
8361 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01008362 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01008363 else if (!strcmp(args[1], "dontlognull")) {
8364 /* don't log empty requests */
8365 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008366 }
willy tarreaub952e1d2005-12-18 01:31:20 +01008367 else if (!strcmp(args[1], "tcpka")) {
8368 /* enable TCP keep-alives on client and server sessions */
8369 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
8370 }
8371 else if (!strcmp(args[1], "clitcpka")) {
8372 /* enable TCP keep-alives on client sessions */
8373 curproxy->options |= PR_O_TCP_CLI_KA;
8374 }
8375 else if (!strcmp(args[1], "srvtcpka")) {
8376 /* enable TCP keep-alives on server sessions */
8377 curproxy->options |= PR_O_TCP_SRV_KA;
8378 }
Willy TARREAU3481c462006-03-01 22:37:57 +01008379 else if (!strcmp(args[1], "allbackups")) {
8380 /* Use all backup servers simultaneously */
8381 curproxy->options |= PR_O_USE_ALL_BK;
8382 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008383 else if (!strcmp(args[1], "httpchk")) {
8384 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008385 if (curproxy->check_req != NULL) {
8386 free(curproxy->check_req);
8387 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008388 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01008389 if (!*args[2]) { /* no argument */
8390 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
8391 curproxy->check_len = strlen(DEF_CHECK_REQ);
8392 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01008393 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
8394 curproxy->check_req = (char *)malloc(reqlen);
8395 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
8396 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008397 } else { /* more arguments : METHOD URI [HTTP_VER] */
8398 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
8399 if (*args[4])
8400 reqlen += strlen(args[4]);
8401 else
8402 reqlen += strlen("HTTP/1.0");
8403
8404 curproxy->check_req = (char *)malloc(reqlen);
8405 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
8406 "%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 +01008407 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008408 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008409 else if (!strcmp(args[1], "persist")) {
8410 /* persist on using the server specified by the cookie, even when it's down */
8411 curproxy->options |= PR_O_PERSIST;
8412 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008413 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008414 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008415 return -1;
8416 }
8417 return 0;
8418 }
8419 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
8420 /* enable reconnections to dispatch */
8421 curproxy->options |= PR_O_REDISP;
8422 }
willy tarreaua1598082005-12-17 13:08:06 +01008423#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01008424 else if (!strcmp(args[0], "transparent")) {
8425 /* enable transparent proxy connections */
8426 curproxy->options |= PR_O_TRANSP;
8427 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008428#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01008429 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
8430 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008431 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008432 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008433 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008434 curproxy->maxconn = atol(args[1]);
8435 }
8436 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
8437 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008438 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008439 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008440 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008441 curproxy->grace = atol(args[1]);
8442 }
8443 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01008444 if (curproxy == &defproxy) {
8445 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8446 return -1;
8447 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008448 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008449 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008450 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008451 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008452 curproxy->dispatch_addr = *str2sa(args[1]);
8453 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008454 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01008455 if (*(args[1])) {
8456 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008457 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01008458 }
willy tarreau1a3442d2006-03-24 21:03:20 +01008459 else if (!strcmp(args[1], "source")) {
8460 curproxy->options |= PR_O_BALANCE_SH;
8461 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008462 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01008463 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008464 return -1;
8465 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008466 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008467 else /* if no option is set, use round-robin by default */
8468 curproxy->options |= PR_O_BALANCE_RR;
8469 }
8470 else if (!strcmp(args[0], "server")) { /* server address */
8471 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008472 char *rport;
8473 char *raddr;
8474 short realport;
8475 int do_check;
8476
8477 if (curproxy == &defproxy) {
8478 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8479 return -1;
8480 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008481
willy tarreaua41a8b42005-12-17 14:02:24 +01008482 if (!*args[2]) {
8483 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008484 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008485 return -1;
8486 }
8487 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
8488 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8489 return -1;
8490 }
willy tarreau0174f312005-12-18 01:02:42 +01008491
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008492 /* the servers are linked backwards first */
8493 newsrv->next = curproxy->srv;
8494 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01008495 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008496
willy tarreau18a957c2006-04-12 19:26:23 +02008497 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01008498 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01008499 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01008500 newsrv->id = strdup(args[1]);
8501
8502 /* several ways to check the port component :
8503 * - IP => port=+0, relative
8504 * - IP: => port=+0, relative
8505 * - IP:N => port=N, absolute
8506 * - IP:+N => port=+N, relative
8507 * - IP:-N => port=-N, relative
8508 */
8509 raddr = strdup(args[2]);
8510 rport = strchr(raddr, ':');
8511 if (rport) {
8512 *rport++ = 0;
8513 realport = atol(rport);
8514 if (!isdigit((int)*rport))
8515 newsrv->state |= SRV_MAPPORTS;
8516 } else {
8517 realport = 0;
8518 newsrv->state |= SRV_MAPPORTS;
8519 }
8520
8521 newsrv->addr = *str2sa(raddr);
8522 newsrv->addr.sin_port = htons(realport);
8523 free(raddr);
8524
willy tarreau9fe663a2005-12-17 13:02:59 +01008525 newsrv->curfd = -1; /* no health-check in progress */
8526 newsrv->inter = DEF_CHKINTR;
8527 newsrv->rise = DEF_RISETIME;
8528 newsrv->fall = DEF_FALLTIME;
8529 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
8530 cur_arg = 3;
8531 while (*args[cur_arg]) {
8532 if (!strcmp(args[cur_arg], "cookie")) {
8533 newsrv->cookie = strdup(args[cur_arg + 1]);
8534 newsrv->cklen = strlen(args[cur_arg + 1]);
8535 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01008536 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008537 else if (!strcmp(args[cur_arg], "rise")) {
8538 newsrv->rise = atol(args[cur_arg + 1]);
8539 newsrv->health = newsrv->rise;
8540 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01008541 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008542 else if (!strcmp(args[cur_arg], "fall")) {
8543 newsrv->fall = atol(args[cur_arg + 1]);
8544 cur_arg += 2;
8545 }
8546 else if (!strcmp(args[cur_arg], "inter")) {
8547 newsrv->inter = atol(args[cur_arg + 1]);
8548 cur_arg += 2;
8549 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008550 else if (!strcmp(args[cur_arg], "port")) {
8551 newsrv->check_port = atol(args[cur_arg + 1]);
8552 cur_arg += 2;
8553 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008554 else if (!strcmp(args[cur_arg], "backup")) {
8555 newsrv->state |= SRV_BACKUP;
8556 cur_arg ++;
8557 }
willy tarreaue3f023f2006-04-08 21:52:24 +02008558 else if (!strcmp(args[cur_arg], "weight")) {
8559 int w;
8560 w = atol(args[cur_arg + 1]);
8561 if (w < 1 || w > 256) {
8562 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
8563 file, linenum, newsrv->id, w);
8564 return -1;
8565 }
8566 newsrv->uweight = w - 1;
8567 cur_arg += 2;
8568 }
willy tarreauf76e6ca2006-05-21 21:09:55 +02008569 else if (!strcmp(args[cur_arg], "minconn")) {
8570 newsrv->minconn = atol(args[cur_arg + 1]);
8571 cur_arg += 2;
8572 }
willy tarreau18a957c2006-04-12 19:26:23 +02008573 else if (!strcmp(args[cur_arg], "maxconn")) {
8574 newsrv->maxconn = atol(args[cur_arg + 1]);
8575 cur_arg += 2;
8576 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008577 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01008578 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01008579 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008580 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008581 }
willy tarreau0174f312005-12-18 01:02:42 +01008582 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
8583 if (!*args[cur_arg + 1]) {
8584 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
8585 file, linenum, "source");
8586 return -1;
8587 }
8588 newsrv->state |= SRV_BIND_SRC;
8589 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
8590 cur_arg += 2;
8591 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008592 else {
willy tarreauf76e6ca2006-05-21 21:09:55 +02008593 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port', 'source', 'minconn', 'maxconn' and 'weight'.\n",
willy tarreaua41a8b42005-12-17 14:02:24 +01008594 file, linenum, newsrv->id);
8595 return -1;
8596 }
8597 }
8598
8599 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008600 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
8601 newsrv->check_port = realport; /* by default */
8602 if (!newsrv->check_port) {
8603 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 +01008604 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01008605 return -1;
8606 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008607 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01008608 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008609
willy tarreau62084d42006-03-24 18:57:41 +01008610 if (newsrv->state & SRV_BACKUP)
8611 curproxy->srv_bck++;
8612 else
8613 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01008614 }
8615 else if (!strcmp(args[0], "log")) { /* syslog server address */
8616 struct sockaddr_in *sa;
8617 int facility;
8618
8619 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
8620 curproxy->logfac1 = global.logfac1;
8621 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01008622 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008623 curproxy->logfac2 = global.logfac2;
8624 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01008625 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01008626 }
8627 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01008628 int level;
8629
willy tarreau0f7af912005-12-17 12:21:26 +01008630 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
8631 if (!strcmp(log_facilities[facility], args[2]))
8632 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01008633
willy tarreau0f7af912005-12-17 12:21:26 +01008634 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008635 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01008636 exit(1);
8637 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008638
willy tarreau8337c6b2005-12-17 13:41:01 +01008639 level = 7; /* max syslog level = debug */
8640 if (*(args[3])) {
8641 while (level >= 0 && strcmp(log_levels[level], args[3]))
8642 level--;
8643 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008644 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008645 exit(1);
8646 }
8647 }
8648
willy tarreau0f7af912005-12-17 12:21:26 +01008649 sa = str2sa(args[1]);
8650 if (!sa->sin_port)
8651 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01008652
willy tarreau0f7af912005-12-17 12:21:26 +01008653 if (curproxy->logfac1 == -1) {
8654 curproxy->logsrv1 = *sa;
8655 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01008656 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01008657 }
8658 else if (curproxy->logfac2 == -1) {
8659 curproxy->logsrv2 = *sa;
8660 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01008661 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01008662 }
8663 else {
8664 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01008665 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008666 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008667 }
8668 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008669 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01008670 file, linenum);
8671 return -1;
8672 }
8673 }
willy tarreaua1598082005-12-17 13:08:06 +01008674 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01008675 if (!*args[1]) {
8676 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008677 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01008678 return -1;
8679 }
8680
8681 curproxy->source_addr = *str2sa(args[1]);
8682 curproxy->options |= PR_O_BIND_SRC;
8683 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008684 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
8685 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008686 if (curproxy == &defproxy) {
8687 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8688 return -1;
8689 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008690
8691 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008692 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8693 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008694 return -1;
8695 }
8696
8697 preg = calloc(1, sizeof(regex_t));
8698 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008699 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008700 return -1;
8701 }
8702
willy tarreauc1f47532005-12-18 01:08:26 +01008703 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8704 if (err) {
8705 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8706 file, linenum, *err);
8707 return -1;
8708 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008709 }
8710 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
8711 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008712 if (curproxy == &defproxy) {
8713 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8714 return -1;
8715 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008716
8717 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008718 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008719 return -1;
8720 }
8721
8722 preg = calloc(1, sizeof(regex_t));
8723 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008724 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008725 return -1;
8726 }
8727
8728 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8729 }
8730 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
8731 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008732 if (curproxy == &defproxy) {
8733 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8734 return -1;
8735 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008736
8737 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008738 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008739 return -1;
8740 }
8741
8742 preg = calloc(1, sizeof(regex_t));
8743 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008744 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008745 return -1;
8746 }
8747
8748 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8749 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008750 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
8751 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008752 if (curproxy == &defproxy) {
8753 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8754 return -1;
8755 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008756
8757 if (*(args[1]) == 0) {
8758 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8759 return -1;
8760 }
8761
8762 preg = calloc(1, sizeof(regex_t));
8763 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8764 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8765 return -1;
8766 }
8767
8768 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8769 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008770 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
8771 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008772 if (curproxy == &defproxy) {
8773 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8774 return -1;
8775 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008776
8777 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008778 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008779 return -1;
8780 }
8781
8782 preg = calloc(1, sizeof(regex_t));
8783 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008784 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008785 return -1;
8786 }
8787
8788 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8789 }
8790 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
8791 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008792 if (curproxy == &defproxy) {
8793 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8794 return -1;
8795 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008796
8797 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008798 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8799 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008800 return -1;
8801 }
8802
8803 preg = calloc(1, sizeof(regex_t));
8804 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008805 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008806 return -1;
8807 }
8808
willy tarreauc1f47532005-12-18 01:08:26 +01008809 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8810 if (err) {
8811 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8812 file, linenum, *err);
8813 return -1;
8814 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008815 }
8816 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
8817 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008818 if (curproxy == &defproxy) {
8819 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8820 return -1;
8821 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008822
8823 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008824 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008825 return -1;
8826 }
8827
8828 preg = calloc(1, sizeof(regex_t));
8829 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008830 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008831 return -1;
8832 }
8833
8834 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8835 }
8836 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
8837 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008838 if (curproxy == &defproxy) {
8839 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8840 return -1;
8841 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008842
8843 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008844 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008845 return -1;
8846 }
8847
8848 preg = calloc(1, sizeof(regex_t));
8849 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008850 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008851 return -1;
8852 }
8853
8854 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8855 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008856 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
8857 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008858 if (curproxy == &defproxy) {
8859 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8860 return -1;
8861 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008862
8863 if (*(args[1]) == 0) {
8864 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8865 return -1;
8866 }
8867
8868 preg = calloc(1, sizeof(regex_t));
8869 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8870 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8871 return -1;
8872 }
8873
8874 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8875 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008876 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
8877 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008878 if (curproxy == &defproxy) {
8879 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8880 return -1;
8881 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008882
8883 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008884 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008885 return -1;
8886 }
8887
8888 preg = calloc(1, sizeof(regex_t));
8889 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008890 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008891 return -1;
8892 }
8893
8894 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8895 }
8896 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008897 if (curproxy == &defproxy) {
8898 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8899 return -1;
8900 }
8901
willy tarreau9fe663a2005-12-17 13:02:59 +01008902 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008903 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008904 return 0;
8905 }
8906
8907 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008908 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008909 return -1;
8910 }
8911
willy tarreau4302f492005-12-18 01:00:37 +01008912 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
8913 }
8914 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
8915 regex_t *preg;
8916
8917 if (*(args[1]) == 0 || *(args[2]) == 0) {
8918 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8919 file, linenum, args[0]);
8920 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008921 }
willy tarreau4302f492005-12-18 01:00:37 +01008922
8923 preg = calloc(1, sizeof(regex_t));
8924 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8925 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8926 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008927 }
willy tarreau4302f492005-12-18 01:00:37 +01008928
willy tarreauc1f47532005-12-18 01:08:26 +01008929 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8930 if (err) {
8931 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8932 file, linenum, *err);
8933 return -1;
8934 }
willy tarreau4302f492005-12-18 01:00:37 +01008935 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008936 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
8937 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008938 if (curproxy == &defproxy) {
8939 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8940 return -1;
8941 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008942
8943 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008944 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008945 return -1;
8946 }
willy tarreaue39cd132005-12-17 13:00:18 +01008947
willy tarreau9fe663a2005-12-17 13:02:59 +01008948 preg = calloc(1, sizeof(regex_t));
8949 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008950 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008951 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008952 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008953
willy tarreauc1f47532005-12-18 01:08:26 +01008954 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8955 if (err) {
8956 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8957 file, linenum, *err);
8958 return -1;
8959 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008960 }
willy tarreau982249e2005-12-18 00:57:06 +01008961 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
8962 regex_t *preg;
8963 if (curproxy == &defproxy) {
8964 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8965 return -1;
8966 }
8967
8968 if (*(args[1]) == 0) {
8969 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8970 return -1;
8971 }
8972
8973 preg = calloc(1, sizeof(regex_t));
8974 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8975 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8976 return -1;
8977 }
8978
willy tarreauc1f47532005-12-18 01:08:26 +01008979 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8980 if (err) {
8981 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8982 file, linenum, *err);
8983 return -1;
8984 }
willy tarreau982249e2005-12-18 00:57:06 +01008985 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008986 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01008987 regex_t *preg;
8988 if (curproxy == &defproxy) {
8989 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8990 return -1;
8991 }
willy tarreaue39cd132005-12-17 13:00:18 +01008992
willy tarreaua41a8b42005-12-17 14:02:24 +01008993 if (*(args[1]) == 0 || *(args[2]) == 0) {
8994 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8995 file, linenum, args[0]);
8996 return -1;
8997 }
willy tarreaue39cd132005-12-17 13:00:18 +01008998
willy tarreaua41a8b42005-12-17 14:02:24 +01008999 preg = calloc(1, sizeof(regex_t));
9000 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
9001 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
9002 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01009003 }
willy tarreaua41a8b42005-12-17 14:02:24 +01009004
willy tarreauc1f47532005-12-18 01:08:26 +01009005 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
9006 if (err) {
9007 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
9008 file, linenum, *err);
9009 return -1;
9010 }
willy tarreaua41a8b42005-12-17 14:02:24 +01009011 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009012 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
9013 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01009014 if (curproxy == &defproxy) {
9015 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9016 return -1;
9017 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009018
9019 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009020 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009021 return -1;
9022 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009023
willy tarreau9fe663a2005-12-17 13:02:59 +01009024 preg = calloc(1, sizeof(regex_t));
9025 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009026 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009027 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01009028 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009029
willy tarreauc1f47532005-12-18 01:08:26 +01009030 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
9031 if (err) {
9032 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
9033 file, linenum, *err);
9034 return -1;
9035 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009036 }
willy tarreau982249e2005-12-18 00:57:06 +01009037 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
9038 regex_t *preg;
9039 if (curproxy == &defproxy) {
9040 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9041 return -1;
9042 }
9043
9044 if (*(args[1]) == 0) {
9045 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
9046 return -1;
9047 }
9048
9049 preg = calloc(1, sizeof(regex_t));
9050 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
9051 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
9052 return -1;
9053 }
9054
willy tarreauc1f47532005-12-18 01:08:26 +01009055 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
9056 if (err) {
9057 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
9058 file, linenum, *err);
9059 return -1;
9060 }
willy tarreau982249e2005-12-18 00:57:06 +01009061 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009062 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01009063 if (curproxy == &defproxy) {
9064 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9065 return -1;
9066 }
9067
willy tarreau9fe663a2005-12-17 13:02:59 +01009068 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009069 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009070 return 0;
9071 }
9072
9073 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009074 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009075 return -1;
9076 }
9077
9078 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
9079 }
willy tarreauc1f47532005-12-18 01:08:26 +01009080 else if (!strcmp(args[0], "errorloc") ||
9081 !strcmp(args[0], "errorloc302") ||
9082 !strcmp(args[0], "errorloc303")) { /* error location */
9083 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009084 char *err;
9085
willy tarreaueedaa9f2005-12-17 14:08:03 +01009086 // if (curproxy == &defproxy) {
9087 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9088 // return -1;
9089 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01009090
willy tarreau8337c6b2005-12-17 13:41:01 +01009091 if (*(args[2]) == 0) {
9092 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
9093 return -1;
9094 }
9095
9096 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01009097 if (!strcmp(args[0], "errorloc303")) {
9098 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
9099 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
9100 } else {
9101 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
9102 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
9103 }
willy tarreau8337c6b2005-12-17 13:41:01 +01009104
9105 if (errnum == 400) {
9106 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009107 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009108 free(curproxy->errmsg.msg400);
9109 }
9110 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009111 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009112 }
9113 else if (errnum == 403) {
9114 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009115 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009116 free(curproxy->errmsg.msg403);
9117 }
9118 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009119 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009120 }
9121 else if (errnum == 408) {
9122 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009123 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009124 free(curproxy->errmsg.msg408);
9125 }
9126 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009127 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009128 }
9129 else if (errnum == 500) {
9130 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009131 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009132 free(curproxy->errmsg.msg500);
9133 }
9134 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009135 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009136 }
9137 else if (errnum == 502) {
9138 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009139 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009140 free(curproxy->errmsg.msg502);
9141 }
9142 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009143 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009144 }
9145 else if (errnum == 503) {
9146 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009147 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009148 free(curproxy->errmsg.msg503);
9149 }
9150 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009151 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009152 }
9153 else if (errnum == 504) {
9154 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009155 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009156 free(curproxy->errmsg.msg504);
9157 }
9158 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009159 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009160 }
9161 else {
9162 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
9163 free(err);
9164 }
9165 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009166 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01009167 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01009168 return -1;
9169 }
9170 return 0;
9171}
willy tarreaue39cd132005-12-17 13:00:18 +01009172
willy tarreau5cbea6f2005-12-17 12:48:26 +01009173
willy tarreau9fe663a2005-12-17 13:02:59 +01009174/*
9175 * This function reads and parses the configuration file given in the argument.
9176 * returns 0 if OK, -1 if error.
9177 */
9178int readcfgfile(char *file) {
9179 char thisline[256];
9180 char *line;
9181 FILE *f;
9182 int linenum = 0;
9183 char *end;
9184 char *args[MAX_LINE_ARGS];
9185 int arg;
9186 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01009187 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01009188 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01009189
willy tarreau9fe663a2005-12-17 13:02:59 +01009190 struct proxy *curproxy = NULL;
9191 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01009192
willy tarreau9fe663a2005-12-17 13:02:59 +01009193 if ((f=fopen(file,"r")) == NULL)
9194 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01009195
willy tarreaueedaa9f2005-12-17 14:08:03 +01009196 init_default_instance();
9197
willy tarreau9fe663a2005-12-17 13:02:59 +01009198 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
9199 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009200
willy tarreau9fe663a2005-12-17 13:02:59 +01009201 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01009202
willy tarreau9fe663a2005-12-17 13:02:59 +01009203 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01009204 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01009205 line++;
9206
9207 arg = 0;
9208 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01009209
willy tarreau9fe663a2005-12-17 13:02:59 +01009210 while (*line && arg < MAX_LINE_ARGS) {
9211 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
9212 * C equivalent value. Other combinations left unchanged (eg: \1).
9213 */
9214 if (*line == '\\') {
9215 int skip = 0;
9216 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
9217 *line = line[1];
9218 skip = 1;
9219 }
9220 else if (line[1] == 'r') {
9221 *line = '\r';
9222 skip = 1;
9223 }
9224 else if (line[1] == 'n') {
9225 *line = '\n';
9226 skip = 1;
9227 }
9228 else if (line[1] == 't') {
9229 *line = '\t';
9230 skip = 1;
9231 }
willy tarreauc1f47532005-12-18 01:08:26 +01009232 else if (line[1] == 'x') {
9233 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
9234 unsigned char hex1, hex2;
9235 hex1 = toupper(line[2]) - '0';
9236 hex2 = toupper(line[3]) - '0';
9237 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
9238 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
9239 *line = (hex1<<4) + hex2;
9240 skip = 3;
9241 }
9242 else {
9243 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
9244 return -1;
9245 }
9246 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009247 if (skip) {
9248 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
9249 end -= skip;
9250 }
9251 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01009252 }
willy tarreaua1598082005-12-17 13:08:06 +01009253 else if (*line == '#' || *line == '\n' || *line == '\r') {
9254 /* end of string, end of loop */
9255 *line = 0;
9256 break;
9257 }
willy tarreauc29948c2005-12-17 13:10:27 +01009258 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009259 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01009260 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01009261 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01009262 line++;
9263 args[++arg] = line;
9264 }
9265 else {
9266 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01009267 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009268 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009269
willy tarreau9fe663a2005-12-17 13:02:59 +01009270 /* empty line */
9271 if (!**args)
9272 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01009273
willy tarreau9fe663a2005-12-17 13:02:59 +01009274 /* zero out remaining args */
9275 while (++arg < MAX_LINE_ARGS) {
9276 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009277 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009278
willy tarreaua41a8b42005-12-17 14:02:24 +01009279 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01009280 confsect = CFG_LISTEN;
9281 else if (!strcmp(args[0], "global")) /* global config */
9282 confsect = CFG_GLOBAL;
9283 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01009284
willy tarreau9fe663a2005-12-17 13:02:59 +01009285 switch (confsect) {
9286 case CFG_LISTEN:
9287 if (cfg_parse_listen(file, linenum, args) < 0)
9288 return -1;
9289 break;
9290 case CFG_GLOBAL:
9291 if (cfg_parse_global(file, linenum, args) < 0)
9292 return -1;
9293 break;
9294 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01009295 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009296 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01009297 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009298
9299
willy tarreau0f7af912005-12-17 12:21:26 +01009300 }
9301 fclose(f);
9302
9303 /*
9304 * Now, check for the integrity of all that we have collected.
9305 */
9306
Willy TARREAU3759f982006-03-01 22:44:17 +01009307 /* will be needed further to delay some tasks */
9308 tv_now(&now);
9309
willy tarreau0f7af912005-12-17 12:21:26 +01009310 if ((curproxy = proxy) == NULL) {
9311 Alert("parsing %s : no <listen> line. Nothing to do !\n",
9312 file);
9313 return -1;
9314 }
9315
9316 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01009317 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01009318 curproxy = curproxy->next;
9319 continue;
9320 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009321
9322 if (curproxy->listen == NULL) {
9323 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);
9324 cfgerr++;
9325 }
9326 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01009327 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01009328 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01009329 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
9330 file, curproxy->id);
9331 cfgerr++;
9332 }
9333 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
9334 if (curproxy->options & PR_O_TRANSP) {
9335 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
9336 file, curproxy->id);
9337 cfgerr++;
9338 }
willy tarreau38d79062006-05-21 14:47:13 +02009339#ifdef WE_DONT_SUPPORT_SERVERLESS_LISTENERS
willy tarreau5cbea6f2005-12-17 12:48:26 +01009340 else if (curproxy->srv == NULL) {
9341 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
9342 file, curproxy->id);
9343 cfgerr++;
9344 }
willy tarreau38d79062006-05-21 14:47:13 +02009345#endif
willy tarreaua1598082005-12-17 13:08:06 +01009346 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01009347 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
9348 file, curproxy->id);
9349 }
9350 }
9351 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01009352 if (curproxy->cookie_name != NULL) {
9353 Warning("parsing %s : cookie will be ignored for listener %s.\n",
9354 file, curproxy->id);
9355 }
9356 if ((newsrv = curproxy->srv) != NULL) {
9357 Warning("parsing %s : servers will be ignored for listener %s.\n",
9358 file, curproxy->id);
9359 }
willy tarreaue39cd132005-12-17 13:00:18 +01009360 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01009361 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
9362 file, curproxy->id);
9363 }
willy tarreaue39cd132005-12-17 13:00:18 +01009364 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01009365 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
9366 file, curproxy->id);
9367 }
9368 }
9369 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
9370 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
9371 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
9372 file, curproxy->id);
9373 cfgerr++;
9374 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009375 }
willy tarreaue3f023f2006-04-08 21:52:24 +02009376
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009377 /* first, we will invert the servers list order */
9378 newsrv = NULL;
9379 while (curproxy->srv) {
9380 struct server *next;
9381
9382 next = curproxy->srv->next;
9383 curproxy->srv->next = newsrv;
9384 newsrv = curproxy->srv;
9385 if (!next)
9386 break;
9387 curproxy->srv = next;
9388 }
9389
9390 /* now, newsrv == curproxy->srv */
9391 if (newsrv) {
9392 struct server *srv;
9393 int pgcd;
9394 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02009395
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009396 /* We will factor the weights to reduce the table,
9397 * using Euclide's largest common divisor algorithm
9398 */
9399 pgcd = newsrv->uweight + 1;
9400 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
9401 int t, w;
9402
9403 w = srv->uweight + 1;
9404 while (w) {
9405 t = pgcd % w;
9406 pgcd = w;
9407 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02009408 }
willy tarreau0f7af912005-12-17 12:21:26 +01009409 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009410
9411 act = bck = 0;
9412 for (srv = newsrv; srv; srv = srv->next) {
9413 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
9414 if (srv->state & SRV_BACKUP)
9415 bck += srv->eweight + 1;
9416 else
9417 act += srv->eweight + 1;
9418 }
9419
9420 /* this is the largest map we will ever need for this servers list */
9421 if (act < bck)
9422 act = bck;
9423
9424 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
9425 /* recounts servers and their weights */
9426 recount_servers(curproxy);
9427 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01009428 }
willy tarreau25c4ea52005-12-18 00:49:49 +01009429
9430 if (curproxy->options & PR_O_LOGASAP)
9431 curproxy->to_log &= ~LW_BYTES;
9432
willy tarreau8337c6b2005-12-17 13:41:01 +01009433 if (curproxy->errmsg.msg400 == NULL) {
9434 curproxy->errmsg.msg400 = (char *)HTTP_400;
9435 curproxy->errmsg.len400 = strlen(HTTP_400);
9436 }
9437 if (curproxy->errmsg.msg403 == NULL) {
9438 curproxy->errmsg.msg403 = (char *)HTTP_403;
9439 curproxy->errmsg.len403 = strlen(HTTP_403);
9440 }
9441 if (curproxy->errmsg.msg408 == NULL) {
9442 curproxy->errmsg.msg408 = (char *)HTTP_408;
9443 curproxy->errmsg.len408 = strlen(HTTP_408);
9444 }
9445 if (curproxy->errmsg.msg500 == NULL) {
9446 curproxy->errmsg.msg500 = (char *)HTTP_500;
9447 curproxy->errmsg.len500 = strlen(HTTP_500);
9448 }
9449 if (curproxy->errmsg.msg502 == NULL) {
9450 curproxy->errmsg.msg502 = (char *)HTTP_502;
9451 curproxy->errmsg.len502 = strlen(HTTP_502);
9452 }
9453 if (curproxy->errmsg.msg503 == NULL) {
9454 curproxy->errmsg.msg503 = (char *)HTTP_503;
9455 curproxy->errmsg.len503 = strlen(HTTP_503);
9456 }
9457 if (curproxy->errmsg.msg504 == NULL) {
9458 curproxy->errmsg.msg504 = (char *)HTTP_504;
9459 curproxy->errmsg.len504 = strlen(HTTP_504);
9460 }
Willy TARREAU3759f982006-03-01 22:44:17 +01009461
willy tarreau59a6cc22006-05-12 01:29:08 +02009462 /*
9463 * If this server supports a maxconn parameter, it needs a dedicated
9464 * tasks to fill the emptied slots when a connection leaves.
9465 */
9466 newsrv = curproxy->srv;
9467 while (newsrv != NULL) {
willy tarreauf76e6ca2006-05-21 21:09:55 +02009468 if (newsrv->minconn && !newsrv->maxconn) {
9469 /* only 'minconn' was specified. Let's turn this into maxconn */
9470 newsrv->maxconn = newsrv->minconn;
9471 newsrv->minconn = 0;
9472 }
9473
willy tarreau59a6cc22006-05-12 01:29:08 +02009474 if (newsrv->maxconn > 0) {
9475 struct task *t;
9476
9477 if ((t = pool_alloc(task)) == NULL) {
9478 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
9479 return -1;
9480 }
9481
9482 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
9483 t->wq = LIST_HEAD(wait_queue[1]); /* already assigned to the eternity queue */
9484 t->state = TASK_IDLE;
9485 t->process = process_srv_queue;
9486 t->context = newsrv;
9487 newsrv->queue_mgt = t;
9488
9489 /* never run it unless specifically woken up */
9490 tv_eternity(&t->expire);
9491 task_queue(t);
9492 }
9493 newsrv = newsrv->next;
9494 }
9495
Willy TARREAU3759f982006-03-01 22:44:17 +01009496 /* now we'll start this proxy's health checks if any */
9497 /* 1- count the checkers to run simultaneously */
9498 nbchk = 0;
9499 mininter = 0;
9500 newsrv = curproxy->srv;
9501 while (newsrv != NULL) {
9502 if (newsrv->state & SRV_CHECKED) {
9503 if (!mininter || mininter > newsrv->inter)
9504 mininter = newsrv->inter;
9505 nbchk++;
9506 }
9507 newsrv = newsrv->next;
9508 }
9509
9510 /* 2- start them as far as possible from each others while respecting
9511 * their own intervals. For this, we will start them after their own
9512 * interval added to the min interval divided by the number of servers,
9513 * weighted by the server's position in the list.
9514 */
9515 if (nbchk > 0) {
9516 struct task *t;
9517 int srvpos;
9518
9519 newsrv = curproxy->srv;
9520 srvpos = 0;
9521 while (newsrv != NULL) {
9522 /* should this server be checked ? */
9523 if (newsrv->state & SRV_CHECKED) {
9524 if ((t = pool_alloc(task)) == NULL) {
9525 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
9526 return -1;
9527 }
9528
9529 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02009530 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
Willy TARREAU3759f982006-03-01 22:44:17 +01009531 t->state = TASK_IDLE;
9532 t->process = process_chk;
9533 t->context = newsrv;
9534
9535 /* check this every ms */
9536 tv_delayfrom(&t->expire, &now,
9537 newsrv->inter + mininter * srvpos / nbchk);
9538 task_queue(t);
9539 //task_wakeup(&rq, t);
9540 srvpos++;
9541 }
9542 newsrv = newsrv->next;
9543 }
9544 }
9545
willy tarreau0f7af912005-12-17 12:21:26 +01009546 curproxy = curproxy->next;
9547 }
9548 if (cfgerr > 0) {
9549 Alert("Errors found in configuration file, aborting.\n");
9550 return -1;
9551 }
9552 else
9553 return 0;
9554}
9555
9556
9557/*
9558 * This function initializes all the necessary variables. It only returns
9559 * if everything is OK. If something fails, it exits.
9560 */
9561void init(int argc, char **argv) {
9562 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01009563 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01009564 char *old_argv = *argv;
9565 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009566 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009567
9568 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01009569 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01009570 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01009571 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01009572 exit(1);
9573 }
9574
willy tarreau746e26b2006-03-25 11:14:35 +01009575#ifdef HAPROXY_MEMMAX
9576 global.rlimit_memmax = HAPROXY_MEMMAX;
9577#endif
9578
Willy TARREAUa9e75f62006-03-01 22:27:48 +01009579 /* initialize the libc's localtime structures once for all so that we
9580 * won't be missing memory if we want to send alerts under OOM conditions.
9581 */
9582 tv_now(&now);
9583 localtime(&now.tv_sec);
willy tarreaue0331262006-05-15 03:02:46 +02009584 start_date = now;
Willy TARREAUa9e75f62006-03-01 22:27:48 +01009585
willy tarreau4302f492005-12-18 01:00:37 +01009586 /* initialize the log header encoding map : '{|}"#' should be encoded with
9587 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
9588 * URL encoding only requires '"', '#' to be encoded as well as non-
9589 * printable characters above.
9590 */
9591 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
9592 memset(url_encode_map, 0, sizeof(url_encode_map));
9593 for (i = 0; i < 32; i++) {
9594 FD_SET(i, hdr_encode_map);
9595 FD_SET(i, url_encode_map);
9596 }
9597 for (i = 127; i < 256; i++) {
9598 FD_SET(i, hdr_encode_map);
9599 FD_SET(i, url_encode_map);
9600 }
9601
9602 tmp = "\"#{|}";
9603 while (*tmp) {
9604 FD_SET(*tmp, hdr_encode_map);
9605 tmp++;
9606 }
9607
9608 tmp = "\"#";
9609 while (*tmp) {
9610 FD_SET(*tmp, url_encode_map);
9611 tmp++;
9612 }
9613
willy tarreau64a3cc32005-12-18 01:13:11 +01009614 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
9615#if defined(ENABLE_POLL)
9616 cfg_polling_mechanism |= POLL_USE_POLL;
9617#endif
9618#if defined(ENABLE_EPOLL)
9619 cfg_polling_mechanism |= POLL_USE_EPOLL;
9620#endif
9621
willy tarreau0f7af912005-12-17 12:21:26 +01009622 pid = getpid();
9623 progname = *argv;
9624 while ((tmp = strchr(progname, '/')) != NULL)
9625 progname = tmp + 1;
9626
9627 argc--; argv++;
9628 while (argc > 0) {
9629 char *flag;
9630
9631 if (**argv == '-') {
9632 flag = *argv+1;
9633
9634 /* 1 arg */
9635 if (*flag == 'v') {
9636 display_version();
9637 exit(0);
9638 }
willy tarreau1c2ad212005-12-18 01:11:29 +01009639#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009640 else if (*flag == 'd' && flag[1] == 'e')
9641 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009642#endif
9643#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009644 else if (*flag == 'd' && flag[1] == 'p')
9645 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009646#endif
willy tarreau982249e2005-12-18 00:57:06 +01009647 else if (*flag == 'V')
9648 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009649 else if (*flag == 'd' && flag[1] == 'b')
9650 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01009651 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01009652 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01009653 else if (*flag == 'c')
9654 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01009655 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01009656 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009657 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01009658 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01009659 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
9660 /* list of pids to finish ('f') or terminate ('t') */
9661
9662 if (flag[1] == 'f')
9663 oldpids_sig = SIGUSR1; /* finish then exit */
9664 else
9665 oldpids_sig = SIGTERM; /* terminate immediately */
9666 argv++; argc--;
9667
9668 if (argc > 0) {
9669 oldpids = calloc(argc, sizeof(int));
9670 while (argc > 0) {
9671 oldpids[nb_oldpids] = atol(*argv);
9672 if (oldpids[nb_oldpids] <= 0)
9673 usage(old_argv);
9674 argc--; argv++;
9675 nb_oldpids++;
9676 }
9677 }
9678 }
willy tarreau2c513732006-04-15 19:25:16 +02009679#if STATTIME > 0
9680 else if (*flag == 's')
9681 arg_mode |= MODE_STATS;
9682 else if (*flag == 'l')
9683 arg_mode |= MODE_LOG;
9684#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009685 else { /* >=2 args */
9686 argv++; argc--;
9687 if (argc == 0)
9688 usage(old_argv);
9689
9690 switch (*flag) {
9691 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01009692 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01009693 case 'N' : cfg_maxpconn = atol(*argv); break;
9694 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009695 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01009696 default: usage(old_argv);
9697 }
9698 }
9699 }
9700 else
9701 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01009702 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01009703 }
9704
willy tarreaud0fb4652005-12-18 01:32:04 +01009705 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009706 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
9707 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01009708
willy tarreau0f7af912005-12-17 12:21:26 +01009709 if (!cfg_cfgfile)
9710 usage(old_argv);
9711
9712 gethostname(hostname, MAX_HOSTNAME_LEN);
9713
willy tarreau12350152005-12-18 01:03:27 +01009714 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01009715 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01009716 if (readcfgfile(cfg_cfgfile) < 0) {
9717 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
9718 exit(1);
9719 }
willy tarreau12350152005-12-18 01:03:27 +01009720 if (have_appsession)
9721 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01009722
willy tarreau982249e2005-12-18 00:57:06 +01009723 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01009724 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
9725 exit(0);
9726 }
9727
willy tarreau9fe663a2005-12-17 13:02:59 +01009728 if (cfg_maxconn > 0)
9729 global.maxconn = cfg_maxconn;
9730
willy tarreaufe2c5c12005-12-17 14:14:34 +01009731 if (cfg_pidfile) {
9732 if (global.pidfile)
9733 free(global.pidfile);
9734 global.pidfile = strdup(cfg_pidfile);
9735 }
9736
willy tarreau9fe663a2005-12-17 13:02:59 +01009737 if (global.maxconn == 0)
9738 global.maxconn = DEFAULT_MAXCONN;
9739
Willy TARREAU203b0b62006-03-12 18:00:28 +01009740 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01009741
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009742 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009743 /* command line debug mode inhibits configuration mode */
9744 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
9745 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009746 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
9747 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01009748
9749 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
9750 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
9751 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
9752 }
9753
9754 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009755 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
9756 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01009757 global.nbproc = 1;
9758 }
9759
9760 if (global.nbproc < 1)
9761 global.nbproc = 1;
9762
willy tarreau0f7af912005-12-17 12:21:26 +01009763 StaticReadEvent = (fd_set *)calloc(1,
9764 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01009765 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01009766 StaticWriteEvent = (fd_set *)calloc(1,
9767 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01009768 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01009769
9770 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01009771 sizeof(struct fdtab) * (global.maxsock));
9772 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01009773 fdtab[i].state = FD_STCLOSE;
9774 }
9775}
9776
9777/*
willy tarreau41310e72006-03-25 18:17:56 +01009778 * this function starts all the proxies. Its return value is composed from
9779 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
9780 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01009781 */
willy tarreau41310e72006-03-25 18:17:56 +01009782int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01009783 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01009784 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01009785 int err = ERR_NONE;
9786 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01009787
9788 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01009789 if (curproxy->state != PR_STNEW)
9790 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01009791
willy tarreau41310e72006-03-25 18:17:56 +01009792 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01009793 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01009794 if (listener->fd != -1)
9795 continue; /* already initialized */
9796
9797 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
9798 if (verbose)
9799 Alert("cannot create listening socket for proxy %s. Aborting.\n",
9800 curproxy->id);
9801 err |= ERR_RETRYABLE;
9802 pxerr |= 1;
9803 continue;
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 (fd >= global.maxsock) {
9807 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
9808 curproxy->id);
9809 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009810 err |= ERR_FATAL;
9811 pxerr |= 1;
9812 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009813 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009814
willy tarreaua41a8b42005-12-17 14:02:24 +01009815 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
9816 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
9817 (char *) &one, sizeof(one)) == -1)) {
9818 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
9819 curproxy->id);
9820 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009821 err |= ERR_FATAL;
9822 pxerr |= 1;
9823 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009824 }
willy tarreau0f7af912005-12-17 12:21:26 +01009825
willy tarreaua41a8b42005-12-17 14:02:24 +01009826 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
9827 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
9828 curproxy->id);
9829 }
willy tarreau0f7af912005-12-17 12:21:26 +01009830
willy tarreaufac1a862006-05-21 10:20:28 +02009831#ifdef SO_REUSEPORT
9832 /* OpenBSD supports this. As it's present in old libc versions of Linux,
9833 * it might return an error that we will silently ignore.
9834 */
9835 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one));
9836#endif
willy tarreaua41a8b42005-12-17 14:02:24 +01009837 if (bind(fd,
9838 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01009839 listener->addr.ss_family == AF_INET6 ?
9840 sizeof(struct sockaddr_in6) :
9841 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009842 if (verbose)
9843 Alert("cannot bind socket for proxy %s. Aborting.\n",
9844 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009845 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009846 err |= ERR_RETRYABLE;
9847 pxerr |= 1;
9848 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009849 }
willy tarreau0f7af912005-12-17 12:21:26 +01009850
willy tarreaua41a8b42005-12-17 14:02:24 +01009851 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009852 if (verbose)
9853 Alert("cannot listen to socket for proxy %s. Aborting.\n",
9854 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009855 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009856 err |= ERR_RETRYABLE;
9857 pxerr |= 1;
9858 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009859 }
willy tarreau0f7af912005-12-17 12:21:26 +01009860
willy tarreau41310e72006-03-25 18:17:56 +01009861 /* the socket is ready */
9862 listener->fd = fd;
9863
willy tarreaua41a8b42005-12-17 14:02:24 +01009864 /* the function for the accept() event */
9865 fdtab[fd].read = &event_accept;
9866 fdtab[fd].write = NULL; /* never called */
9867 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01009868 fdtab[fd].state = FD_STLISTEN;
9869 FD_SET(fd, StaticReadEvent);
9870 fd_insert(fd);
9871 listeners++;
9872 }
willy tarreau41310e72006-03-25 18:17:56 +01009873
9874 if (!pxerr) {
9875 curproxy->state = PR_STRUN;
9876 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
9877 }
willy tarreau0f7af912005-12-17 12:21:26 +01009878 }
willy tarreau41310e72006-03-25 18:17:56 +01009879
9880 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01009881}
9882
willy tarreaub952e1d2005-12-18 01:31:20 +01009883int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01009884
9885 appsess *temp1,*temp2;
9886 temp1 = (appsess *)key1;
9887 temp2 = (appsess *)key2;
9888
9889 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
9890 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
9891
9892 return (strcmp(temp1->sessid,temp2->sessid) == 0);
9893}/* end match_str */
9894
willy tarreaub952e1d2005-12-18 01:31:20 +01009895void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01009896 appsess *temp1;
9897
9898 //printf("destroy called\n");
9899 temp1 = (appsess *)data;
9900
9901 if (temp1->sessid)
9902 pool_free_to(apools.sessid, temp1->sessid);
9903
9904 if (temp1->serverid)
9905 pool_free_to(apools.serverid, temp1->serverid);
9906
9907 pool_free(appsess, temp1);
9908} /* end destroy */
9909
9910void appsession_cleanup( void )
9911{
9912 struct proxy *p = proxy;
9913
9914 while(p) {
9915 chtbl_destroy(&(p->htbl_proxy));
9916 p = p->next;
9917 }
9918}/* end appsession_cleanup() */
9919
9920void pool_destroy(void **pool)
9921{
9922 void *temp, *next;
9923 next = pool;
9924 while (next) {
9925 temp = next;
9926 next = *(void **)temp;
9927 free(temp);
9928 }
9929}/* end pool_destroy() */
9930
willy tarreaub952e1d2005-12-18 01:31:20 +01009931void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01009932 struct proxy *p = proxy;
9933 struct cap_hdr *h,*h_next;
9934 struct server *s,*s_next;
9935 struct listener *l,*l_next;
9936
9937 while (p) {
9938 if (p->id)
9939 free(p->id);
9940
9941 if (p->check_req)
9942 free(p->check_req);
9943
9944 if (p->cookie_name)
9945 free(p->cookie_name);
9946
9947 if (p->capture_name)
9948 free(p->capture_name);
9949
9950 /* only strup if the user have set in config.
9951 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01009952 if (p->errmsg.msg400) free(p->errmsg.msg400);
9953 if (p->errmsg.msg403) free(p->errmsg.msg403);
9954 if (p->errmsg.msg408) free(p->errmsg.msg408);
9955 if (p->errmsg.msg500) free(p->errmsg.msg500);
9956 if (p->errmsg.msg502) free(p->errmsg.msg502);
9957 if (p->errmsg.msg503) free(p->errmsg.msg503);
9958 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01009959 */
9960 if (p->appsession_name)
9961 free(p->appsession_name);
9962
9963 h = p->req_cap;
9964 while (h) {
9965 h_next = h->next;
9966 if (h->name)
9967 free(h->name);
9968 pool_destroy(h->pool);
9969 free(h);
9970 h = h_next;
9971 }/* end while(h) */
9972
9973 h = p->rsp_cap;
9974 while (h) {
9975 h_next = h->next;
9976 if (h->name)
9977 free(h->name);
9978
9979 pool_destroy(h->pool);
9980 free(h);
9981 h = h_next;
9982 }/* end while(h) */
9983
9984 s = p->srv;
9985 while (s) {
9986 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01009987 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01009988 free(s->id);
9989
willy tarreaub952e1d2005-12-18 01:31:20 +01009990 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01009991 free(s->cookie);
9992
9993 free(s);
9994 s = s_next;
9995 }/* end while(s) */
9996
9997 l = p->listen;
9998 while (l) {
9999 l_next = l->next;
10000 free(l);
10001 l = l_next;
10002 }/* end while(l) */
10003
10004 pool_destroy((void **) p->req_cap_pool);
10005 pool_destroy((void **) p->rsp_cap_pool);
10006 p = p->next;
10007 }/* end while(p) */
10008
10009 if (global.chroot) free(global.chroot);
10010 if (global.pidfile) free(global.pidfile);
10011
willy tarreau12350152005-12-18 01:03:27 +010010012 if (StaticReadEvent) free(StaticReadEvent);
10013 if (StaticWriteEvent) free(StaticWriteEvent);
10014 if (fdtab) free(fdtab);
10015
10016 pool_destroy(pool_session);
10017 pool_destroy(pool_buffer);
10018 pool_destroy(pool_fdtab);
10019 pool_destroy(pool_requri);
10020 pool_destroy(pool_task);
10021 pool_destroy(pool_capture);
10022 pool_destroy(pool_appsess);
10023
10024 if (have_appsession) {
10025 pool_destroy(apools.serverid);
10026 pool_destroy(apools.sessid);
10027 }
10028} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +010010029
willy tarreau41310e72006-03-25 18:17:56 +010010030/* sends the signal <sig> to all pids found in <oldpids> */
10031static void tell_old_pids(int sig) {
10032 int p;
10033 for (p = 0; p < nb_oldpids; p++)
10034 kill(oldpids[p], sig);
10035}
10036
willy tarreau0f7af912005-12-17 12:21:26 +010010037int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +010010038 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +010010039 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +010010040 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +010010041 init(argc, argv);
10042
willy tarreau0f7af912005-12-17 12:21:26 +010010043 signal(SIGQUIT, dump);
10044 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +010010045 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +010010046#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +010010047 signal(SIGINT, sig_int);
10048 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +010010049#endif
willy tarreau0f7af912005-12-17 12:21:26 +010010050
10051 /* on very high loads, a sigpipe sometimes happen just between the
10052 * getsockopt() which tells "it's OK to write", and the following write :-(
10053 */
willy tarreau3242e862005-12-17 12:27:53 +010010054#ifndef MSG_NOSIGNAL
10055 signal(SIGPIPE, SIG_IGN);
10056#endif
willy tarreau0f7af912005-12-17 12:21:26 +010010057
willy tarreau41310e72006-03-25 18:17:56 +010010058 /* We will loop at most 100 times with 10 ms delay each time.
10059 * That's at most 1 second. We only send a signal to old pids
10060 * if we cannot grab at least one port.
10061 */
10062 retry = MAX_START_RETRIES;
10063 err = ERR_NONE;
10064 while (retry >= 0) {
10065 struct timeval w;
10066 err = start_proxies(retry == 0 || nb_oldpids == 0);
10067 if (err != ERR_RETRYABLE)
10068 break;
10069 if (nb_oldpids == 0)
10070 break;
10071
Willy TARREAU007aa462006-05-14 09:55:23 +020010072 /* FIXME-20060514: Solaris and OpenBSD do not support shutdown() on
10073 * listening sockets. So on those platforms, it would be wiser to
10074 * simply send SIGUSR1, which will not be undoable.
10075 */
willy tarreau41310e72006-03-25 18:17:56 +010010076 tell_old_pids(SIGTTOU);
10077 /* give some time to old processes to stop listening */
10078 w.tv_sec = 0;
10079 w.tv_usec = 10*1000;
10080 select(0, NULL, NULL, NULL, &w);
10081 retry--;
10082 }
10083
10084 /* Note: start_proxies() sends an alert when it fails. */
10085 if (err != ERR_NONE) {
10086 if (retry != MAX_START_RETRIES && nb_oldpids)
10087 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +010010088 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +010010089 }
willy tarreaud0fb4652005-12-18 01:32:04 +010010090
10091 if (listeners == 0) {
10092 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +010010093 /* Note: we don't have to send anything to the old pids because we
10094 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +010010095 exit(1);
10096 }
10097
willy tarreaudbd3bef2006-01-20 19:35:18 +010010098 /* prepare pause/play signals */
10099 signal(SIGTTOU, sig_pause);
10100 signal(SIGTTIN, sig_listen);
10101
Willy TARREAUe3283d12006-03-01 22:15:29 +010010102 if (global.mode & MODE_DAEMON) {
10103 global.mode &= ~MODE_VERBOSE;
10104 global.mode |= MODE_QUIET;
10105 }
10106
willy tarreaud0fb4652005-12-18 01:32:04 +010010107 /* MODE_QUIET can inhibit alerts and warnings below this line */
10108
10109 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +010010110 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +010010111 /* detach from the tty */
10112 fclose(stdin); fclose(stdout); fclose(stderr);
10113 close(0); close(1); close(2);
10114 }
willy tarreau0f7af912005-12-17 12:21:26 +010010115
willy tarreaufe2c5c12005-12-17 14:14:34 +010010116 /* open log & pid files before the chroot */
10117 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
10118 int pidfd;
10119 unlink(global.pidfile);
10120 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
10121 if (pidfd < 0) {
10122 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +010010123 if (nb_oldpids)
10124 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +010010125 exit(1);
10126 }
10127 pidfile = fdopen(pidfd, "w");
10128 }
willy tarreau9fe663a2005-12-17 13:02:59 +010010129
10130 /* chroot if needed */
10131 if (global.chroot != NULL) {
10132 if (chroot(global.chroot) == -1) {
10133 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +010010134 if (nb_oldpids)
10135 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +010010136 }
10137 chdir("/");
10138 }
10139
willy tarreaub1285d52005-12-18 01:20:14 +010010140 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +010010141 if (!global.rlimit_nofile)
10142 global.rlimit_nofile = global.maxsock;
10143
willy tarreaub1285d52005-12-18 01:20:14 +010010144 if (global.rlimit_nofile) {
10145 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
10146 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
10147 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
10148 }
willy tarreau746e26b2006-03-25 11:14:35 +010010149 }
10150
10151 if (global.rlimit_memmax) {
10152 limit.rlim_cur = limit.rlim_max =
10153 global.rlimit_memmax * 1048576 / global.nbproc;
10154#ifdef RLIMIT_AS
10155 if (setrlimit(RLIMIT_AS, &limit) == -1) {
10156 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
10157 argv[0], global.rlimit_memmax);
10158 }
10159#else
10160 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
10161 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
10162 argv[0], global.rlimit_memmax);
10163 }
10164#endif
willy tarreaub1285d52005-12-18 01:20:14 +010010165 }
10166
willy tarreau41310e72006-03-25 18:17:56 +010010167 if (nb_oldpids)
10168 tell_old_pids(oldpids_sig);
10169
10170 /* Note that any error at this stage will be fatal because we will not
10171 * be able to restart the old pids.
10172 */
10173
willy tarreau9fe663a2005-12-17 13:02:59 +010010174 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +010010175 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +010010176 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
10177 exit(1);
10178 }
10179
willy tarreau036e1ce2005-12-17 13:46:33 +010010180 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +010010181 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
10182 exit(1);
10183 }
10184
willy tarreaub1285d52005-12-18 01:20:14 +010010185 /* check ulimits */
10186 limit.rlim_cur = limit.rlim_max = 0;
10187 getrlimit(RLIMIT_NOFILE, &limit);
10188 if (limit.rlim_cur < global.maxsock) {
10189 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",
10190 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
10191 }
10192
willy tarreau9fe663a2005-12-17 13:02:59 +010010193 if (global.mode & MODE_DAEMON) {
10194 int ret = 0;
10195 int proc;
10196
10197 /* the father launches the required number of processes */
10198 for (proc = 0; proc < global.nbproc; proc++) {
10199 ret = fork();
10200 if (ret < 0) {
10201 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +010010202 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +010010203 exit(1); /* there has been an error */
10204 }
10205 else if (ret == 0) /* child breaks here */
10206 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +010010207 if (pidfile != NULL) {
10208 fprintf(pidfile, "%d\n", ret);
10209 fflush(pidfile);
10210 }
willy tarreau9fe663a2005-12-17 13:02:59 +010010211 }
willy tarreaufe2c5c12005-12-17 14:14:34 +010010212 /* close the pidfile both in children and father */
10213 if (pidfile != NULL)
10214 fclose(pidfile);
10215 free(global.pidfile);
10216
willy tarreau9fe663a2005-12-17 13:02:59 +010010217 if (proc == global.nbproc)
10218 exit(0); /* parent must leave */
10219
willy tarreau750a4722005-12-17 13:21:24 +010010220 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
10221 * that we can detach from the TTY. We MUST NOT do it in other cases since
10222 * it would have already be done, and 0-2 would have been affected to listening
10223 * sockets
10224 */
10225 if (!(global.mode & MODE_QUIET)) {
10226 /* detach from the tty */
10227 fclose(stdin); fclose(stdout); fclose(stderr);
10228 close(0); close(1); close(2); /* close all fd's */
10229 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
10230 }
willy tarreaua1598082005-12-17 13:08:06 +010010231 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +010010232 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +010010233 }
10234
willy tarreau1c2ad212005-12-18 01:11:29 +010010235#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +010010236 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010237 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
10238 epoll_loop(POLL_LOOP_ACTION_RUN);
10239 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010240 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010241 }
10242 else {
willy tarreau64a3cc32005-12-18 01:13:11 +010010243 Warning("epoll() is not available. Using poll()/select() instead.\n");
10244 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010245 }
10246 }
10247#endif
10248
10249#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +010010250 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010251 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
10252 poll_loop(POLL_LOOP_ACTION_RUN);
10253 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010254 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010255 }
10256 else {
10257 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +010010258 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010259 }
10260 }
10261#endif
willy tarreau64a3cc32005-12-18 01:13:11 +010010262 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010263 if (select_loop(POLL_LOOP_ACTION_INIT)) {
10264 select_loop(POLL_LOOP_ACTION_RUN);
10265 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010266 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +010010267 }
10268 }
10269
willy tarreau0f7af912005-12-17 12:21:26 +010010270
willy tarreau12350152005-12-18 01:03:27 +010010271 /* Free all Hash Keys and all Hash elements */
10272 appsession_cleanup();
10273 /* Do some cleanup */
10274 deinit();
10275
willy tarreau0f7af912005-12-17 12:21:26 +010010276 exit(0);
10277}
willy tarreau12350152005-12-18 01:03:27 +010010278
10279#if defined(DEBUG_HASH)
10280static void print_table(const CHTbl *htbl) {
10281
10282 ListElmt *element;
10283 int i;
10284 appsess *asession;
10285
10286 /*****************************************************************************
10287 * *
10288 * Display the chained hash table. *
10289 * *
10290 *****************************************************************************/
10291
10292 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
10293
10294 for (i = 0; i < TBLSIZ; i++) {
10295 fprintf(stdout, "Bucket[%03d]\n", i);
10296
10297 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
10298 //fprintf(stdout, "%c", *(char *)list_data(element));
10299 asession = (appsess *)list_data(element);
10300 fprintf(stdout, "ELEM :%s:", asession->sessid);
10301 fprintf(stdout, " Server :%s: \n", asession->serverid);
10302 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
10303 }
10304
10305 fprintf(stdout, "\n");
10306 }
10307 return;
10308} /* end print_table */
10309#endif
10310
10311static int appsession_init(void)
10312{
10313 static int initialized = 0;
10314 int idlen;
10315 struct server *s;
10316 struct proxy *p = proxy;
10317
10318 if (!initialized) {
10319 if (!appsession_task_init()) {
10320 apools.sessid = NULL;
10321 apools.serverid = NULL;
10322 apools.ser_waste = 0;
10323 apools.ser_use = 0;
10324 apools.ser_msize = sizeof(void *);
10325 apools.ses_waste = 0;
10326 apools.ses_use = 0;
10327 apools.ses_msize = sizeof(void *);
10328 while (p) {
10329 s = p->srv;
10330 if (apools.ses_msize < p->appsession_len)
10331 apools.ses_msize = p->appsession_len;
10332 while (s) {
10333 idlen = strlen(s->id);
10334 if (apools.ser_msize < idlen)
10335 apools.ser_msize = idlen;
10336 s = s->next;
10337 }
10338 p = p->next;
10339 }
10340 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
10341 apools.ses_msize ++;
10342 }
10343 else {
10344 fprintf(stderr, "appsession_task_init failed\n");
10345 return -1;
10346 }
10347 initialized ++;
10348 }
10349 return 0;
10350}
10351
10352static int appsession_task_init(void)
10353{
10354 static int initialized = 0;
10355 struct task *t;
10356 if (!initialized) {
10357 if ((t = pool_alloc(task)) == NULL)
10358 return -1;
10359 t->next = t->prev = t->rqnext = NULL;
willy tarreau5e698ef2006-05-02 14:51:00 +020010360 t->wq = LIST_HEAD(wait_queue[0]);
willy tarreau12350152005-12-18 01:03:27 +010010361 t->state = TASK_IDLE;
10362 t->context = NULL;
10363 tv_delayfrom(&t->expire, &now, TBLCHKINT);
10364 task_queue(t);
10365 t->process = appsession_refresh;
10366 initialized ++;
10367 }
10368 return 0;
10369}
10370
10371static int appsession_refresh(struct task *t) {
10372 struct proxy *p = proxy;
10373 CHTbl *htbl;
10374 ListElmt *element, *last;
10375 int i;
10376 appsess *asession;
10377 void *data;
10378
10379 while (p) {
10380 if (p->appsession_name != NULL) {
10381 htbl = &p->htbl_proxy;
10382 /* if we ever give up the use of TBLSIZ, we need to change this */
10383 for (i = 0; i < TBLSIZ; i++) {
10384 last = NULL;
10385 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
10386 asession = (appsess *)list_data(element);
10387 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
10388 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
10389 int len;
10390 /*
10391 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
10392 */
10393 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
10394 asession->sessid, asession->serverid?asession->serverid:"(null)");
10395 write(1, trash, len);
10396 }
10397 /* delete the expired element from within the hash table */
10398 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
10399 && (htbl->table[i].destroy != NULL)) {
10400 htbl->table[i].destroy(data);
10401 }
10402 if (last == NULL) {/* patient lost his head, get a new one */
10403 element = list_head(&htbl->table[i]);
10404 if (element == NULL) break; /* no heads left, go to next patient */
10405 }
10406 else
10407 element = last;
10408 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
10409 else
10410 last = element;
10411 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
10412 }
10413 }
10414 p = p->next;
10415 }
10416 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
10417 return TBLCHKINT;
10418} /* end appsession_refresh */
10419
willy tarreau18a957c2006-04-12 19:26:23 +020010420
10421/*
10422 * Local variables:
10423 * c-indent-level: 4
10424 * c-basic-offset: 4
10425 * End:
10426 */