blob: 37ee7573fe4dae0290f082ccfb0ca383732a8179 [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 tarreau5cbea6f2005-12-17 12:48:26 +0100382
willy tarreaua5e8c662006-04-29 10:43:46 +0200383/* various session flags, bits values 0x01 to 0x20 (shift 0) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100384#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
385#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
386#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
387#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
388#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
389#define SN_POST 0x00000020 /* the request was an HTTP POST */
390
willy tarreaua5e8c662006-04-29 10:43:46 +0200391/* session flags dedicated to cookies : bits values 0x40, 0x80 (0-3 shift 6) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100392#define SN_CK_NONE 0x00000000 /* this session had no cookie */
393#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
394#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
395#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
396#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
397#define SN_CK_SHIFT 6 /* bit shift */
398
willy tarreaua5e8c662006-04-29 10:43:46 +0200399/* session termination conditions, bits values 0x100 to 0x700 (0-7 shift 8) */
willy tarreaub1285d52005-12-18 01:20:14 +0100400#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100401#define SN_ERR_CLITO 0x00000100 /* client time-out */
402#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
403#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
404#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
405#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100406#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
407#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100408#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
409#define SN_ERR_SHIFT 8 /* bit shift */
410
willy tarreaua5e8c662006-04-29 10:43:46 +0200411/* session state at termination, bits values 0x1000 to 0x7000 (0-7 shift 12) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100412#define SN_FINST_R 0x00001000 /* session ended during client request */
413#define SN_FINST_C 0x00002000 /* session ended during server connect */
414#define SN_FINST_H 0x00003000 /* session ended during server headers */
415#define SN_FINST_D 0x00004000 /* session ended during data phase */
416#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
willy tarreau078c79a2006-05-13 12:23:58 +0200417#define SN_FINST_Q 0x00006000 /* session ended while waiting in queue for a server slot */
willy tarreau036e1ce2005-12-17 13:46:33 +0100418#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
419#define SN_FINST_SHIFT 12 /* bit shift */
420
willy tarreaua5e8c662006-04-29 10:43:46 +0200421/* cookie information, bits values 0x10000 to 0x80000 (0-8 shift 16) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100422#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
423#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
424#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
425#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
426#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100427#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100428#define SN_SCK_SHIFT 16 /* bit shift */
429
willy tarreaua5e8c662006-04-29 10:43:46 +0200430/* cacheability management, bits values 0x100000 to 0x300000 (0-3 shift 20) */
willy tarreau97f58572005-12-18 00:53:44 +0100431#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
432#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
433#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100434
willy tarreaua5e8c662006-04-29 10:43:46 +0200435/* various other session flags, bits values 0x400000 and above */
436#define SN_MONITOR 0x00400000 /* this session comes from a monitoring system */
willy tarreaudfece232006-05-02 00:19:57 +0200437#define SN_ASSIGNED 0x00800000 /* no need to assign a server to this session */
438#define SN_ADDR_SET 0x01000000 /* this session's server address has been set */
willy tarreaue0331262006-05-15 03:02:46 +0200439#define SN_SELF_GEN 0x02000000 /* the proxy generates data for the client (eg: stats) */
willy tarreaua5e8c662006-04-29 10:43:46 +0200440
willy tarreaue0331262006-05-15 03:02:46 +0200441/* various data sources for the responses */
442#define DATA_SRC_NONE 0
443#define DATA_SRC_STATS 1
willy tarreaua5e8c662006-04-29 10:43:46 +0200444
willy tarreau1f431b52006-05-21 14:46:15 +0200445/* data transmission states for the responses */
446#define DATA_ST_INIT 0
447#define DATA_ST_DATA 1
448
willy tarreau5cbea6f2005-12-17 12:48:26 +0100449/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100450#define CL_STHEADERS 0
451#define CL_STDATA 1
452#define CL_STSHUTR 2
453#define CL_STSHUTW 3
454#define CL_STCLOSE 4
455
willy tarreau5cbea6f2005-12-17 12:48:26 +0100456/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100457#define SV_STIDLE 0
willy tarreau9fea1942006-05-12 19:46:40 +0200458#define SV_STCONN 1
459#define SV_STHEADERS 2
460#define SV_STDATA 3
461#define SV_STSHUTR 4
462#define SV_STSHUTW 5
463#define SV_STCLOSE 6
willy tarreau0f7af912005-12-17 12:21:26 +0100464
465/* result of an I/O event */
466#define RES_SILENT 0 /* didn't happen */
467#define RES_DATA 1 /* data were sent or received */
468#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
469#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
470
willy tarreau9fe663a2005-12-17 13:02:59 +0100471/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100472#define MODE_DEBUG 1
473#define MODE_STATS 2
474#define MODE_LOG 4
475#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100476#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100477#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100478#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100479#define MODE_STARTING 128
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100480#define MODE_FOREGROUND 256
willy tarreau5cbea6f2005-12-17 12:48:26 +0100481
482/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100483#define SRV_RUNNING 1 /* the server is UP */
484#define SRV_BACKUP 2 /* this server is a backup server */
485#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100486#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100487#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100488
willy tarreaudfece232006-05-02 00:19:57 +0200489/* function which act on servers need to return various errors */
490#define SRV_STATUS_OK 0 /* everything is OK. */
491#define SRV_STATUS_INTERNAL 1 /* other unrecoverable errors. */
492#define SRV_STATUS_NOSRV 2 /* no server is available */
493#define SRV_STATUS_FULL 3 /* the/all server(s) are saturated */
494#define SRV_STATUS_QUEUED 4 /* the/all server(s) are saturated but the connection was queued */
495
willy tarreaue39cd132005-12-17 13:00:18 +0100496/* what to do when a header matches a regex */
497#define ACT_ALLOW 0 /* allow the request */
498#define ACT_REPLACE 1 /* replace the matching header */
499#define ACT_REMOVE 2 /* remove the matching header */
500#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100501#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100502
willy tarreau9fe663a2005-12-17 13:02:59 +0100503/* configuration sections */
504#define CFG_NONE 0
505#define CFG_GLOBAL 1
506#define CFG_LISTEN 2
507
willy tarreaua1598082005-12-17 13:08:06 +0100508/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100509#define LW_DATE 1 /* date */
510#define LW_CLIP 2 /* CLient IP */
511#define LW_SVIP 4 /* SerVer IP */
512#define LW_SVID 8 /* server ID */
513#define LW_REQ 16 /* http REQuest */
514#define LW_RESP 32 /* http RESPonse */
515#define LW_PXIP 64 /* proxy IP */
516#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100517#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100518#define LW_COOKIE 512 /* captured cookie */
519#define LW_REQHDR 1024 /* request header(s) */
520#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100521
willy tarreau41310e72006-03-25 18:17:56 +0100522#define ERR_NONE 0 /* no error */
523#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
524#define ERR_FATAL 2 /* fatal error, may be cumulated */
525
willy tarreau0f7af912005-12-17 12:21:26 +0100526/*********************************************************************/
527
528#define LIST_HEAD(a) ((void *)(&(a)))
529
530/*********************************************************************/
531
willy tarreau9e138862006-05-14 23:06:28 +0200532/* describes a chunk of string */
533struct chunk {
534 char *str; /* beginning of the string itself. Might not be 0-terminated */
535 int len; /* size of the string from first to last char. <0 = uninit. */
536};
537
willy tarreau4302f492005-12-18 01:00:37 +0100538struct cap_hdr {
539 struct cap_hdr *next;
540 char *name; /* header name, case insensitive */
541 int namelen; /* length of the header name, to speed-up lookups */
542 int len; /* capture length, not including terminal zero */
543 int index; /* index in the output array */
544 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
545};
546
willy tarreau0f7af912005-12-17 12:21:26 +0100547struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100548 struct hdr_exp *next;
549 regex_t *preg; /* expression to look for */
550 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
551 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100552};
553
554struct buffer {
555 unsigned int l; /* data length */
556 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100557 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100558 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100559 char data[BUFSIZE];
560};
561
willy tarreau18a957c2006-04-12 19:26:23 +0200562struct pendconn {
563 struct list list; /* chaining ... */
564 struct session *sess; /* the session waiting for a connection */
565 struct server *srv; /* the server we are waiting for */
566};
567
willy tarreau0f7af912005-12-17 12:21:26 +0100568struct server {
569 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100570 int state; /* server state (SRV_*) */
571 int cklen; /* the len of the cookie, to speed up checks */
572 char *cookie; /* the id set in the cookie */
573 char *id; /* just for identification */
willy tarreau18a957c2006-04-12 19:26:23 +0200574 struct list pendconns; /* pending connections */
willy tarreaucb406512006-05-18 00:52:35 +0200575 int nbpend, nbpend_max; /* number of pending connections */
willy tarreau59a6cc22006-05-12 01:29:08 +0200576 struct task *queue_mgt; /* the task associated to the queue processing */
willy tarreau0f7af912005-12-17 12:21:26 +0100577 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100578 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100579 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100580 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100581 int rise, fall; /* time in iterations */
582 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100583 int result; /* 0 = connect OK, -1 = connect KO */
584 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreaue3f023f2006-04-08 21:52:24 +0200585 unsigned char uweight, eweight; /* user-specified weight-1, and effective weight-1 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200586 unsigned int wscore; /* weight score, used during srv map computation */
willy tarreaucb406512006-05-18 00:52:35 +0200587 int cur_sess, cur_sess_max; /* number of currently active sessions (including syn_sent) */
willy tarreaua647c702006-04-15 22:45:52 +0200588 unsigned int cum_sess; /* cumulated number of sessions really sent to this server */
willy tarreau18a957c2006-04-12 19:26:23 +0200589 unsigned int maxconn; /* max # of active sessions. 0 = unlimited. */
willy tarreaucb406512006-05-18 00:52:35 +0200590 unsigned failed_checks, down_trans; /* failed checks and up-down transitions */
willy tarreau535ae7a2005-12-17 12:58:00 +0100591 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100592};
593
willy tarreau5cbea6f2005-12-17 12:48:26 +0100594/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100595struct task {
596 struct task *next, *prev; /* chaining ... */
597 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100598 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100599 int state; /* task state : IDLE or RUNNING */
600 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100601 int (*process)(struct task *t); /* the function which processes the task */
602 void *context; /* the task's context */
603};
604
605/* WARNING: if new fields are added, they must be initialized in event_accept() */
606struct session {
607 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100608 /* application specific below */
609 struct timeval crexpire; /* expiration date for a client read */
610 struct timeval cwexpire; /* expiration date for a client write */
611 struct timeval srexpire; /* expiration date for a server read */
612 struct timeval swexpire; /* expiration date for a server write */
613 struct timeval cnexpire; /* expiration date for a connect */
614 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
615 struct proxy *proxy; /* the proxy this socket belongs to */
616 int cli_fd; /* the client side fd */
617 int srv_fd; /* the server side fd */
618 int cli_state; /* state of the client side */
619 int srv_state; /* state of the server side */
620 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100621 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100622 struct buffer *req; /* request buffer */
623 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100624 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100625 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100626 struct server *srv; /* the server being used */
willy tarreau18a957c2006-04-12 19:26:23 +0200627 struct pendconn *pend_pos; /* if not NULL, points to the position in the pending queue */
willy tarreau4302f492005-12-18 01:00:37 +0100628 char **req_cap; /* array of captured request headers (may be NULL) */
629 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreau9e138862006-05-14 23:06:28 +0200630 struct chunk req_line; /* points to first line */
631 struct chunk auth_hdr; /* points to 'Authorization:' header */
willy tarreaua1598082005-12-17 13:08:06 +0100632 struct {
633 int logwait; /* log fields waiting to be collected : LW_* */
634 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
635 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
willy tarreauf32f5242006-05-02 22:54:52 +0200636 long t_queue; /* delay before the session gets out of the connect queue, -1 if never occurs */
willy tarreaua1598082005-12-17 13:08:06 +0100637 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
638 long t_data; /* delay before the first data byte from the server ... */
639 unsigned long t_close; /* total session duration */
willy tarreau5e69b162006-05-12 19:49:37 +0200640 unsigned long srv_queue_size; /* number of sessions waiting for a connect slot on this server at accept() time (in direct assignment) */
641 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 +0100642 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100643 char *cli_cookie; /* cookie presented by the client, in capture mode */
644 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100645 int status; /* HTTP status from the server, negative if from proxy */
646 long long bytes; /* number of bytes transferred from the server */
647 } logs;
willy tarreau1f431b52006-05-21 14:46:15 +0200648 short int data_source; /* where to get the data we generate ourselves */
649 short int data_state; /* where to get the data we generate ourselves */
willy tarreaue0331262006-05-15 03:02:46 +0200650 union {
651 struct {
652 struct proxy *px;
653 struct server *sv;
willy tarreau1f431b52006-05-21 14:46:15 +0200654 short px_st, sv_st; /* DATA_ST_INIT or DATA_ST_DATA */
willy tarreaue0331262006-05-15 03:02:46 +0200655 } stats;
656 } data_ctx;
willy tarreau2f6ba652005-12-17 13:57:42 +0100657 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100658};
659
willy tarreaua41a8b42005-12-17 14:02:24 +0100660struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100661 int fd; /* the listen socket */
662 struct sockaddr_storage addr; /* the address we listen to */
663 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100664};
willy tarreauf32f5242006-05-02 22:54:52 +0200665
willy tarreau0f7af912005-12-17 12:21:26 +0100666struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100667 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100668 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 +0100669 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100670 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200671 struct server *srv; /* known servers */
672 int srv_act, srv_bck; /* # of running servers */
673 int tot_wact, tot_wbck; /* total weights of active and backup servers */
674 struct server **srv_map; /* the server map used to apply weights */
675 int srv_map_sz; /* the size of the effective server map */
676 int srv_rr_idx; /* next server to be elected in round robin mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100677 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100678 int cookie_len; /* strlen(cookie_name), computed only once */
679 char *appsession_name; /* name of the cookie to look for */
680 int appsession_name_len; /* strlen(appsession_name), computed only once */
681 int appsession_len; /* length of the appsession cookie value to be used */
682 int appsession_timeout;
683 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100684 char *capture_name; /* beginning of the name of the cookie to capture */
685 int capture_namelen; /* length of the cookie name to match */
686 int capture_len; /* length of the string to be captured */
willy tarreau9e138862006-05-14 23:06:28 +0200687 struct uri_auth *uri_auth; /* if non-NULL, the (list of) per-URI authentications */
willy tarreau0f7af912005-12-17 12:21:26 +0100688 int clitimeout; /* client I/O timeout (in milliseconds) */
689 int srvtimeout; /* server I/O timeout (in milliseconds) */
690 int contimeout; /* connect timeout (in milliseconds) */
691 char *id; /* proxy id */
willy tarreaudfece232006-05-02 00:19:57 +0200692 struct list pendconns; /* pending connections with no server assigned yet */
willy tarreaucb406512006-05-18 00:52:35 +0200693 int nbpend, nbpend_max; /* number of pending connections with no server assigned yet */
willy tarreauf32f5242006-05-02 22:54:52 +0200694 int totpend; /* total number of pending connections on this instance (for stats) */
willy tarreaucb406512006-05-18 00:52:35 +0200695 int nbconn, nbconn_max; /* # of active sessions */
willy tarreau14b4d432006-04-07 18:23:29 +0200696 unsigned int cum_conn; /* cumulated number of processed sessions */
willy tarreau0f7af912005-12-17 12:21:26 +0100697 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100698 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100699 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100700 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100701 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100702 struct proxy *next;
703 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100704 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100705 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100706 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100707 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100708 int nb_reqadd, nb_rspadd;
709 struct hdr_exp *req_exp; /* regular expressions for request headers */
710 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100711 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
712 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
713 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
714 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100715 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100716 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100717 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
718 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100719 struct {
720 char *msg400; /* message for error 400 */
721 int len400; /* message length for error 400 */
722 char *msg403; /* message for error 403 */
723 int len403; /* message length for error 403 */
724 char *msg408; /* message for error 408 */
725 int len408; /* message length for error 408 */
726 char *msg500; /* message for error 500 */
727 int len500; /* message length for error 500 */
728 char *msg502; /* message for error 502 */
729 int len502; /* message length for error 502 */
730 char *msg503; /* message for error 503 */
731 int len503; /* message length for error 503 */
732 char *msg504; /* message for error 504 */
733 int len504; /* message length for error 504 */
734 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100735};
736
737/* info about one given fd */
738struct fdtab {
739 int (*read)(int fd); /* read function */
740 int (*write)(int fd); /* write function */
741 struct task *owner; /* the session (or proxy) associated with this fd */
742 int state; /* the state of this fd */
743};
744
745/*********************************************************************/
746
willy tarreaub952e1d2005-12-18 01:31:20 +0100747int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100748int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100749char *cfg_cfgfile = NULL; /* configuration file */
750char *progname = NULL; /* program name */
751int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100752
753/* global options */
754static struct {
755 int uid;
756 int gid;
757 int nbproc;
758 int maxconn;
759 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100760 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100761 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100762 int mode;
763 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100764 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100765 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100766 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100767 struct sockaddr_in logsrv1, logsrv2;
768} global = {
769 logfac1 : -1,
770 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100771 loglev1 : 7, /* max syslog level : debug */
772 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100773 /* others NULL OK */
774};
775
willy tarreau0f7af912005-12-17 12:21:26 +0100776/*********************************************************************/
777
willy tarreau1c2ad212005-12-18 01:11:29 +0100778fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100779 *StaticWriteEvent;
780
willy tarreau64a3cc32005-12-18 01:13:11 +0100781int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100782
willy tarreau0f7af912005-12-17 12:21:26 +0100783void **pool_session = NULL,
willy tarreau18a957c2006-04-12 19:26:23 +0200784 **pool_pendconn = NULL,
willy tarreau0f7af912005-12-17 12:21:26 +0100785 **pool_buffer = NULL,
786 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100787 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100788 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100789 **pool_capture = NULL,
790 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100791
792struct proxy *proxy = NULL; /* list of all existing proxies */
793struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100794struct task *rq = NULL; /* global run queue */
willy tarreau5e698ef2006-05-02 14:51:00 +0200795struct task wait_queue[2] = { /* global wait queue */
796 {
797 prev:LIST_HEAD(wait_queue[0]), /* expirable tasks */
798 next:LIST_HEAD(wait_queue[0]),
799 },
800 {
801 prev:LIST_HEAD(wait_queue[1]), /* non-expirable tasks */
802 next:LIST_HEAD(wait_queue[1]),
803 },
willy tarreau5cbea6f2005-12-17 12:48:26 +0100804};
willy tarreau0f7af912005-12-17 12:21:26 +0100805
willy tarreau0f7af912005-12-17 12:21:26 +0100806static int totalconn = 0; /* total # of terminated sessions */
807static int actconn = 0; /* # of active sessions */
808static int maxfd = 0; /* # of the highest fd + 1 */
809static int listeners = 0; /* # of listeners */
810static int stopping = 0; /* non zero means stopping in progress */
811static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaue0331262006-05-15 03:02:46 +0200812static struct timeval start_date; /* the process's start date */
willy tarreaua41a8b42005-12-17 14:02:24 +0100813static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100814
willy tarreau53e99702006-03-25 18:53:50 +0100815/* Here we store informations about the pids of the processes we may pause
816 * or kill. We will send them a signal every 10 ms until we can bind to all
817 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100818 */
willy tarreau53e99702006-03-25 18:53:50 +0100819#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100820static int nb_oldpids = 0;
821static int *oldpids = NULL;
822static int oldpids_sig; /* use USR1 or TERM */
823
willy tarreau08dedbe2005-12-18 01:13:48 +0100824#if defined(ENABLE_EPOLL)
825/* FIXME: this is dirty, but at the moment, there's no other solution to remove
826 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
827 * structure with pointers to functions such as init_fd() and close_fd(), plus
828 * a private structure with several pointers to places such as below.
829 */
830
831static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
832#endif
833
willy tarreau0f7af912005-12-17 12:21:26 +0100834static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100835/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100836static char trash[BUFSIZE];
837
willy tarreaudd07e972005-12-18 00:48:48 +0100838const int zero = 0;
839const int one = 1;
840
willy tarreau0f7af912005-12-17 12:21:26 +0100841/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100842 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100843 */
844
845#define MAX_SYSLOG_LEN 1024
846#define NB_LOG_FACILITIES 24
847const char *log_facilities[NB_LOG_FACILITIES] = {
848 "kern", "user", "mail", "daemon",
849 "auth", "syslog", "lpr", "news",
850 "uucp", "cron", "auth2", "ftp",
851 "ntp", "audit", "alert", "cron2",
852 "local0", "local1", "local2", "local3",
853 "local4", "local5", "local6", "local7"
854};
855
856
857#define NB_LOG_LEVELS 8
858const char *log_levels[NB_LOG_LEVELS] = {
859 "emerg", "alert", "crit", "err",
860 "warning", "notice", "info", "debug"
861};
862
863#define SYSLOG_PORT 514
864
865const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
866 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100867
willy tarreaub1285d52005-12-18 01:20:14 +0100868const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau078c79a2006-05-13 12:23:58 +0200869const char sess_fin_state[8] = "-RCHDLQ7"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, unknown */
willy tarreau036e1ce2005-12-17 13:46:33 +0100870const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
871const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
872 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
873 unknown, Set-cookie Rewritten */
874
willy tarreau0f7af912005-12-17 12:21:26 +0100875#define MAX_HOSTNAME_LEN 32
876static char hostname[MAX_HOSTNAME_LEN] = "";
877
willy tarreau8337c6b2005-12-17 13:41:01 +0100878const char *HTTP_302 =
879 "HTTP/1.0 302 Found\r\n"
880 "Cache-Control: no-cache\r\n"
881 "Connection: close\r\n"
882 "Location: "; /* not terminated since it will be concatenated with the URL */
883
willy tarreauc1f47532005-12-18 01:08:26 +0100884/* same as 302 except that the browser MUST retry with the GET method */
885const char *HTTP_303 =
886 "HTTP/1.0 303 See Other\r\n"
887 "Cache-Control: no-cache\r\n"
888 "Connection: close\r\n"
889 "Location: "; /* not terminated since it will be concatenated with the URL */
890
willy tarreaua1598082005-12-17 13:08:06 +0100891const char *HTTP_400 =
892 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100893 "Cache-Control: no-cache\r\n"
894 "Connection: close\r\n"
895 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100896 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100897
willy tarreau9e138862006-05-14 23:06:28 +0200898/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
899const char *HTTP_401_fmt =
900 "HTTP/1.0 401 Unauthorized\r\n"
901 "Cache-Control: no-cache\r\n"
902 "Connection: close\r\n"
903 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
904 "\r\n"
905 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
906
willy tarreaua1598082005-12-17 13:08:06 +0100907const char *HTTP_403 =
908 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100909 "Cache-Control: no-cache\r\n"
910 "Connection: close\r\n"
911 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100912 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
913
willy tarreau8337c6b2005-12-17 13:41:01 +0100914const char *HTTP_408 =
915 "HTTP/1.0 408 Request Time-out\r\n"
916 "Cache-Control: no-cache\r\n"
917 "Connection: close\r\n"
918 "\r\n"
919 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
920
willy tarreau750a4722005-12-17 13:21:24 +0100921const char *HTTP_500 =
922 "HTTP/1.0 500 Server Error\r\n"
923 "Cache-Control: no-cache\r\n"
924 "Connection: close\r\n"
925 "\r\n"
926 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100927
928const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100929 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100930 "Cache-Control: no-cache\r\n"
931 "Connection: close\r\n"
932 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100933 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
934
935const char *HTTP_503 =
936 "HTTP/1.0 503 Service Unavailable\r\n"
937 "Cache-Control: no-cache\r\n"
938 "Connection: close\r\n"
939 "\r\n"
940 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
941
942const char *HTTP_504 =
943 "HTTP/1.0 504 Gateway Time-out\r\n"
944 "Cache-Control: no-cache\r\n"
945 "Connection: close\r\n"
946 "\r\n"
947 "<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 +0100948
willy tarreau0f7af912005-12-17 12:21:26 +0100949/*********************************************************************/
950/* statistics ******************************************************/
951/*********************************************************************/
952
willy tarreau750a4722005-12-17 13:21:24 +0100953#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100954static int stats_tsk_lsrch, stats_tsk_rsrch,
955 stats_tsk_good, stats_tsk_right, stats_tsk_left,
956 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100957#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100958
959
960/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100961/* debugging *******************************************************/
962/*********************************************************************/
963#ifdef DEBUG_FULL
964static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau3504a012006-05-14 23:20:07 +0200965static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau750a4722005-12-17 13:21:24 +0100966#endif
967
968/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100969/* function prototypes *********************************************/
970/*********************************************************************/
971
972int event_accept(int fd);
973int event_cli_read(int fd);
974int event_cli_write(int fd);
975int event_srv_read(int fd);
976int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100977int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100978
willy tarreau12350152005-12-18 01:03:27 +0100979static int appsession_task_init(void);
980static int appsession_init(void);
981static int appsession_refresh(struct task *t);
982
willy tarreau0f7af912005-12-17 12:21:26 +0100983/*********************************************************************/
984/* general purpose functions ***************************************/
985/*********************************************************************/
986
987void display_version() {
988 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100989 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100990}
991
992/*
993 * This function prints the command line usage and exits
994 */
995void usage(char *name) {
996 display_version();
997 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100998 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100999#if STATTIME > 0
1000 "sl"
1001#endif
willy tarreau746e26b2006-03-25 11:14:35 +01001002 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
1003 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +01001004 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +01001005 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +01001006 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +01001007#if STATTIME > 0
1008 " -s enables statistics output\n"
1009 " -l enables long statistics format\n"
1010#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001011 " -D goes daemon ; implies -q\n"
1012 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +01001013 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +01001014 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +01001015 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +01001016 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +01001017 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001018#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01001019 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001020#endif
1021#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01001022 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001023#endif
willy tarreau53e99702006-03-25 18:53:50 +01001024 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +01001025 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01001026 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +01001027 exit(1);
1028}
1029
1030
1031/*
willy tarreaud0fb4652005-12-18 01:32:04 +01001032 * Displays the message on stderr with the date and pid. Overrides the quiet
1033 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +01001034 */
1035void Alert(char *fmt, ...) {
1036 va_list argp;
1037 struct timeval tv;
1038 struct tm *tm;
1039
willy tarreaud0fb4652005-12-18 01:32:04 +01001040 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001041 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +01001042
willy tarreau5cbea6f2005-12-17 12:48:26 +01001043 gettimeofday(&tv, NULL);
1044 tm=localtime(&tv.tv_sec);
1045 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001046 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001047 vfprintf(stderr, fmt, argp);
1048 fflush(stderr);
1049 va_end(argp);
1050 }
willy tarreau0f7af912005-12-17 12:21:26 +01001051}
1052
1053
1054/*
1055 * Displays the message on stderr with the date and pid.
1056 */
1057void Warning(char *fmt, ...) {
1058 va_list argp;
1059 struct timeval tv;
1060 struct tm *tm;
1061
willy tarreau982249e2005-12-18 00:57:06 +01001062 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001063 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +01001064
willy tarreau5cbea6f2005-12-17 12:48:26 +01001065 gettimeofday(&tv, NULL);
1066 tm=localtime(&tv.tv_sec);
1067 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001068 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001069 vfprintf(stderr, fmt, argp);
1070 fflush(stderr);
1071 va_end(argp);
1072 }
1073}
1074
1075/*
1076 * Displays the message on <out> only if quiet mode is not set.
1077 */
1078void qfprintf(FILE *out, char *fmt, ...) {
1079 va_list argp;
1080
willy tarreau982249e2005-12-18 00:57:06 +01001081 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001082 va_start(argp, fmt);
1083 vfprintf(out, fmt, argp);
1084 fflush(out);
1085 va_end(argp);
1086 }
willy tarreau0f7af912005-12-17 12:21:26 +01001087}
1088
1089
1090/*
1091 * converts <str> to a struct sockaddr_in* which is locally allocated.
1092 * The format is "addr:port", where "addr" can be empty or "*" to indicate
1093 * INADDR_ANY.
1094 */
1095struct sockaddr_in *str2sa(char *str) {
1096 static struct sockaddr_in sa;
1097 char *c;
1098 int port;
1099
willy tarreaua1598082005-12-17 13:08:06 +01001100 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +01001101 str=strdup(str);
1102
1103 if ((c=strrchr(str,':')) != NULL) {
1104 *c++=0;
1105 port=atol(c);
1106 }
1107 else
1108 port=0;
1109
1110 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1111 sa.sin_addr.s_addr = INADDR_ANY;
1112 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01001113 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001114 struct hostent *he;
1115
1116 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001117 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001118 }
1119 else
1120 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1121 }
1122 sa.sin_port=htons(port);
1123 sa.sin_family=AF_INET;
1124
1125 free(str);
1126 return &sa;
1127}
1128
willy tarreaub1285d52005-12-18 01:20:14 +01001129/*
1130 * converts <str> to a two struct in_addr* which are locally allocated.
1131 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1132 * is optionnal and either in the dotted or CIDR notation.
1133 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1134 */
1135int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1136 char *c;
1137 unsigned long len;
1138
1139 memset(mask, 0, sizeof(*mask));
1140 memset(addr, 0, sizeof(*addr));
1141 str=strdup(str);
1142
1143 if ((c = strrchr(str, '/')) != NULL) {
1144 *c++ = 0;
1145 /* c points to the mask */
1146 if (strchr(c, '.') != NULL) { /* dotted notation */
1147 if (!inet_pton(AF_INET, c, mask))
1148 return 0;
1149 }
1150 else { /* mask length */
1151 char *err;
1152 len = strtol(c, &err, 10);
1153 if (!*c || (err && *err) || (unsigned)len > 32)
1154 return 0;
1155 if (len)
1156 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1157 else
1158 mask->s_addr = 0;
1159 }
1160 }
1161 else {
1162 mask->s_addr = 0xFFFFFFFF;
1163 }
1164 if (!inet_pton(AF_INET, str, addr)) {
1165 struct hostent *he;
1166
1167 if ((he = gethostbyname(str)) == NULL) {
1168 return 0;
1169 }
1170 else
1171 *addr = *(struct in_addr *) *(he->h_addr_list);
1172 }
1173 free(str);
1174 return 1;
1175}
1176
willy tarreau9fe663a2005-12-17 13:02:59 +01001177
1178/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001179 * converts <str> to a list of listeners which are dynamically allocated.
1180 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1181 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1182 * - <port> is a numerical port from 1 to 65535 ;
1183 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1184 * This can be repeated as many times as necessary, separated by a coma.
1185 * The <tail> argument is a pointer to a current list which should be appended
1186 * to the tail of the new list. The pointer to the new list is returned.
1187 */
1188struct listener *str2listener(char *str, struct listener *tail) {
1189 struct listener *l;
1190 char *c, *next, *range, *dupstr;
1191 int port, end;
1192
1193 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001194
willy tarreaua41a8b42005-12-17 14:02:24 +01001195 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001196 struct sockaddr_storage ss;
1197
willy tarreaua41a8b42005-12-17 14:02:24 +01001198 str = next;
1199 /* 1) look for the end of the first address */
1200 if ((next = strrchr(str, ',')) != NULL) {
1201 *next++ = 0;
1202 }
1203
willy tarreau8a86dbf2005-12-18 00:45:59 +01001204 /* 2) look for the addr/port delimiter, it's the last colon. */
1205 if ((range = strrchr(str, ':')) == NULL) {
1206 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001207 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001208 }
1209
1210 *range++ = 0;
1211
1212 if (strrchr(str, ':') != NULL) {
1213 /* IPv6 address contains ':' */
1214 memset(&ss, 0, sizeof(ss));
1215 ss.ss_family = AF_INET6;
1216
1217 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1218 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001219 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001220 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001221 }
1222 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001223 memset(&ss, 0, sizeof(ss));
1224 ss.ss_family = AF_INET;
1225
1226 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1227 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1228 }
1229 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1230 struct hostent *he;
1231
1232 if ((he = gethostbyname(str)) == NULL) {
1233 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001234 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001235 }
1236 else
1237 ((struct sockaddr_in *)&ss)->sin_addr =
1238 *(struct in_addr *) *(he->h_addr_list);
1239 }
1240 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001241
1242 /* 3) look for the port-end delimiter */
1243 if ((c = strchr(range, '-')) != NULL) {
1244 *c++ = 0;
1245 end = atol(c);
1246 }
1247 else {
1248 end = atol(range);
1249 }
1250
willy tarreaud0fb4652005-12-18 01:32:04 +01001251 port = atol(range);
1252
1253 if (port < 1 || port > 65535) {
1254 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1255 goto fail;
1256 }
1257
1258 if (end < 1 || end > 65535) {
1259 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1260 goto fail;
1261 }
1262
1263 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001264 l = (struct listener *)calloc(1, sizeof(struct listener));
1265 l->next = tail;
1266 tail = l;
1267
willy tarreau41310e72006-03-25 18:17:56 +01001268 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001269 l->addr = ss;
1270 if (ss.ss_family == AF_INET6)
1271 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1272 else
1273 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1274
willy tarreaua41a8b42005-12-17 14:02:24 +01001275 } /* end for(port) */
1276 } /* end while(next) */
1277 free(dupstr);
1278 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001279 fail:
1280 free(dupstr);
1281 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001282}
1283
willy tarreau4302f492005-12-18 01:00:37 +01001284
1285#define FD_SETS_ARE_BITFIELDS
1286#ifdef FD_SETS_ARE_BITFIELDS
1287/*
1288 * This map is used with all the FD_* macros to check whether a particular bit
1289 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1290 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1291 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1292 * exclusively to the macros.
1293 */
1294fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1295fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1296
1297#else
1298#error "Check if your OS uses bitfields for fd_sets"
1299#endif
1300
1301/* will try to encode the string <string> replacing all characters tagged in
1302 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1303 * prefixed by <escape>, and will store the result between <start> (included
1304 *) and <stop> (excluded), and will always terminate the string with a '\0'
1305 * before <stop>. The position of the '\0' is returned if the conversion
1306 * completes. If bytes are missing between <start> and <stop>, then the
1307 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1308 * cannot even be stored so we return <start> without writing the 0.
1309 * The input string must also be zero-terminated.
1310 */
1311char hextab[16] = "0123456789ABCDEF";
1312char *encode_string(char *start, char *stop,
1313 const char escape, const fd_set *map,
1314 const char *string)
1315{
1316 if (start < stop) {
1317 stop--; /* reserve one byte for the final '\0' */
1318 while (start < stop && *string != 0) {
1319 if (!FD_ISSET((unsigned char)(*string), map))
1320 *start++ = *string;
1321 else {
1322 if (start + 3 >= stop)
1323 break;
1324 *start++ = escape;
1325 *start++ = hextab[(*string >> 4) & 15];
1326 *start++ = hextab[*string & 15];
1327 }
1328 string++;
1329 }
1330 *start = '\0';
1331 }
1332 return start;
1333}
willy tarreaua41a8b42005-12-17 14:02:24 +01001334
1335/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001336 * This function sends a syslog message to both log servers of a proxy,
1337 * or to global log servers if the proxy is NULL.
1338 * It also tries not to waste too much time computing the message header.
1339 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001340 */
1341void send_log(struct proxy *p, int level, char *message, ...) {
1342 static int logfd = -1; /* syslog UDP socket */
1343 static long tvsec = -1; /* to force the string to be initialized */
1344 struct timeval tv;
1345 va_list argp;
1346 static char logmsg[MAX_SYSLOG_LEN];
1347 static char *dataptr = NULL;
1348 int fac_level;
1349 int hdr_len, data_len;
1350 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001351 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001352 int nbloggers = 0;
1353 char *log_ptr;
1354
1355 if (logfd < 0) {
1356 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1357 return;
1358 }
1359
1360 if (level < 0 || progname == NULL || message == NULL)
1361 return;
1362
1363 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001364 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001365 /* this string is rebuild only once a second */
1366 struct tm *tm = localtime(&tv.tv_sec);
1367 tvsec = tv.tv_sec;
1368
willy tarreauc29948c2005-12-17 13:10:27 +01001369 hdr_len = snprintf(logmsg, sizeof(logmsg),
1370 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1371 monthname[tm->tm_mon],
1372 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1373 progname, pid);
1374 /* WARNING: depending upon implementations, snprintf may return
1375 * either -1 or the number of bytes that would be needed to store
1376 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001377 */
willy tarreauc29948c2005-12-17 13:10:27 +01001378 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1379 hdr_len = sizeof(logmsg);
1380
1381 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001382 }
1383
1384 va_start(argp, message);
1385 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001386 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1387 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001388 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001389 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001390
1391 if (p == NULL) {
1392 if (global.logfac1 >= 0) {
1393 sa[nbloggers] = &global.logsrv1;
1394 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001395 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001396 nbloggers++;
1397 }
1398 if (global.logfac2 >= 0) {
1399 sa[nbloggers] = &global.logsrv2;
1400 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001401 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001402 nbloggers++;
1403 }
1404 } else {
1405 if (p->logfac1 >= 0) {
1406 sa[nbloggers] = &p->logsrv1;
1407 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001408 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001409 nbloggers++;
1410 }
1411 if (p->logfac2 >= 0) {
1412 sa[nbloggers] = &p->logsrv2;
1413 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001414 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001415 nbloggers++;
1416 }
1417 }
1418
1419 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001420 /* we can filter the level of the messages that are sent to each logger */
1421 if (level > loglevel[nbloggers])
1422 continue;
1423
willy tarreauc29948c2005-12-17 13:10:27 +01001424 /* For each target, we may have a different facility.
1425 * We can also have a different log level for each message.
1426 * This induces variations in the message header length.
1427 * Since we don't want to recompute it each time, nor copy it every
1428 * time, we only change the facility in the pre-computed header,
1429 * and we change the pointer to the header accordingly.
1430 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001431 fac_level = (facilities[nbloggers] << 3) + level;
1432 log_ptr = logmsg + 3; /* last digit of the log level */
1433 do {
1434 *log_ptr = '0' + fac_level % 10;
1435 fac_level /= 10;
1436 log_ptr--;
1437 } while (fac_level && log_ptr > logmsg);
1438 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001439
willy tarreauc29948c2005-12-17 13:10:27 +01001440 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001441
1442#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001443 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001444 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1445#else
willy tarreauc29948c2005-12-17 13:10:27 +01001446 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001447 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1448#endif
1449 }
willy tarreau0f7af912005-12-17 12:21:26 +01001450}
1451
1452
1453/* sets <tv> to the current time */
1454static inline struct timeval *tv_now(struct timeval *tv) {
1455 if (tv)
1456 gettimeofday(tv, NULL);
1457 return tv;
1458}
1459
1460/*
1461 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1462 */
willy tarreaudab722b2006-05-04 19:23:38 +02001463static struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
willy tarreau0f7af912005-12-17 12:21:26 +01001464 if (!tv || !from)
1465 return NULL;
1466 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1467 tv->tv_sec = from->tv_sec + (ms/1000);
1468 while (tv->tv_usec >= 1000000) {
1469 tv->tv_usec -= 1000000;
1470 tv->tv_sec++;
1471 }
1472 return tv;
1473}
1474
1475/*
1476 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001477 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001478 */
1479static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001480 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001481 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001482 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001483 return 1;
1484 else if (tv1->tv_usec < tv2->tv_usec)
1485 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001486 else if (tv1->tv_usec > tv2->tv_usec)
1487 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001488 else
1489 return 0;
1490}
1491
1492/*
1493 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001494 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001495 */
1496unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1497 int cmp;
1498 unsigned long ret;
1499
1500
willy tarreauef900ab2005-12-17 12:52:52 +01001501 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001502 if (!cmp)
1503 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001504 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001505 struct timeval *tmp = tv1;
1506 tv1 = tv2;
1507 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001508 }
willy tarreauef900ab2005-12-17 12:52:52 +01001509 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001510 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001511 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001512 else
willy tarreauef900ab2005-12-17 12:52:52 +01001513 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001514 return (unsigned long) ret;
1515}
1516
1517/*
willy tarreau750a4722005-12-17 13:21:24 +01001518 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001519 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001520 */
1521static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1522 unsigned long ret;
1523
willy tarreau6e682ce2005-12-17 13:26:49 +01001524 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1525 if (tv2->tv_usec > tv1->tv_usec)
1526 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001527 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001528 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001529 return (unsigned long) ret;
1530}
1531
1532/*
willy tarreau0f7af912005-12-17 12:21:26 +01001533 * 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 +01001534 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001535 */
willy tarreaudab722b2006-05-04 19:23:38 +02001536static int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001537 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001538 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001539 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001540 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001541 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001542 else
1543 return 0;
1544 }
willy tarreau0f7af912005-12-17 12:21:26 +01001545 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001546 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001547 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001548 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001549 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001550 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001551 else
1552 return 0;
1553}
1554
1555/*
1556 * returns the remaining time between tv1=now and event=tv2
1557 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001558 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001559 */
1560static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1561 unsigned long ret;
1562
willy tarreau0f7af912005-12-17 12:21:26 +01001563 if (tv_cmp_ms(tv1, tv2) >= 0)
1564 return 0; /* event elapsed */
1565
willy tarreauef900ab2005-12-17 12:52:52 +01001566 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001567 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001568 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001569 else
willy tarreauef900ab2005-12-17 12:52:52 +01001570 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001571 return (unsigned long) ret;
1572}
1573
1574
1575/*
1576 * zeroes a struct timeval
1577 */
1578
1579static inline struct timeval *tv_eternity(struct timeval *tv) {
1580 tv->tv_sec = tv->tv_usec = 0;
1581 return tv;
1582}
1583
1584/*
1585 * returns 1 if tv is null, else 0
1586 */
1587static inline int tv_iseternity(struct timeval *tv) {
1588 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1589 return 1;
1590 else
1591 return 0;
1592}
1593
1594/*
1595 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1596 * considering that 0 is the eternity.
1597 */
willy tarreaudab722b2006-05-04 19:23:38 +02001598static int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001599 if (tv_iseternity(tv1))
1600 if (tv_iseternity(tv2))
1601 return 0; /* same */
1602 else
1603 return 1; /* tv1 later than tv2 */
1604 else if (tv_iseternity(tv2))
1605 return -1; /* tv2 later than tv1 */
1606
1607 if (tv1->tv_sec > tv2->tv_sec)
1608 return 1;
1609 else if (tv1->tv_sec < tv2->tv_sec)
1610 return -1;
1611 else if (tv1->tv_usec > tv2->tv_usec)
1612 return 1;
1613 else if (tv1->tv_usec < tv2->tv_usec)
1614 return -1;
1615 else
1616 return 0;
1617}
1618
1619/*
1620 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1621 * considering that 0 is the eternity.
1622 */
willy tarreaudab722b2006-05-04 19:23:38 +02001623static int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001624 if (tv_iseternity(tv1))
1625 if (tv_iseternity(tv2))
1626 return 0; /* same */
1627 else
1628 return 1; /* tv1 later than tv2 */
1629 else if (tv_iseternity(tv2))
1630 return -1; /* tv2 later than tv1 */
1631
willy tarreauefae1842005-12-17 12:51:03 +01001632 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001633 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001634 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001635 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001636 return -1;
1637 else
1638 return 0;
1639 }
1640 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001641 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001642 return 1;
1643 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001644 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001645 return -1;
1646 else
1647 return 0;
1648}
1649
1650/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001651 * returns the remaining time between tv1=now and event=tv2
1652 * if tv2 is passed, 0 is returned.
1653 * Returns TIME_ETERNITY if tv2 is eternity.
1654 */
willy tarreaudab722b2006-05-04 19:23:38 +02001655static unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001656 unsigned long ret;
1657
1658 if (tv_iseternity(tv2))
1659 return TIME_ETERNITY;
1660
1661 if (tv_cmp_ms(tv1, tv2) >= 0)
1662 return 0; /* event elapsed */
1663
1664 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1665 if (tv2->tv_usec > tv1->tv_usec)
1666 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1667 else
1668 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1669 return (unsigned long) ret;
1670}
1671
1672/*
willy tarreau0f7af912005-12-17 12:21:26 +01001673 * returns the first event between tv1 and tv2 into tvmin.
1674 * a zero tv is ignored. tvmin is returned.
1675 */
1676static inline struct timeval *tv_min(struct timeval *tvmin,
1677 struct timeval *tv1, struct timeval *tv2) {
1678
1679 if (tv_cmp2(tv1, tv2) <= 0)
1680 *tvmin = *tv1;
1681 else
1682 *tvmin = *tv2;
1683
1684 return tvmin;
1685}
1686
1687
1688
1689/***********************************************************/
1690/* fd management ***************************************/
1691/***********************************************************/
1692
1693
1694
willy tarreau5cbea6f2005-12-17 12:48:26 +01001695/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1696 * The file descriptor is also closed.
1697 */
willy tarreaudab722b2006-05-04 19:23:38 +02001698static void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001699 FD_CLR(fd, StaticReadEvent);
1700 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001701#if defined(ENABLE_EPOLL)
1702 if (PrevReadEvent) {
1703 FD_CLR(fd, PrevReadEvent);
1704 FD_CLR(fd, PrevWriteEvent);
1705 }
1706#endif
1707
willy tarreau5cbea6f2005-12-17 12:48:26 +01001708 close(fd);
1709 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001710
1711 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1712 maxfd--;
1713}
1714
1715/* recomputes the maxfd limit from the fd */
1716static inline void fd_insert(int fd) {
1717 if (fd+1 > maxfd)
1718 maxfd = fd+1;
1719}
1720
1721/*************************************************************/
1722/* task management ***************************************/
1723/*************************************************************/
1724
willy tarreau5cbea6f2005-12-17 12:48:26 +01001725/* puts the task <t> in run queue <q>, and returns <t> */
1726static inline struct task *task_wakeup(struct task **q, struct task *t) {
1727 if (t->state == TASK_RUNNING)
1728 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001729 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001730 t->rqnext = *q;
1731 t->state = TASK_RUNNING;
1732 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001733 }
1734}
1735
willy tarreau5cbea6f2005-12-17 12:48:26 +01001736/* removes the task <t> from the queue <q>
1737 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001738 * set the run queue to point to the next one, and return it
1739 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001740static inline struct task *task_sleep(struct task **q, struct task *t) {
1741 if (t->state == TASK_RUNNING) {
1742 *q = t->rqnext;
1743 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001744 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001745 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001746}
1747
1748/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001749 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001750 * from the run queue. A pointer to the task itself is returned.
1751 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001752static inline struct task *task_delete(struct task *t) {
1753 t->prev->next = t->next;
1754 t->next->prev = t->prev;
1755 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001756}
1757
1758/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001759 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001760 */
1761static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001762 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001763}
1764
willy tarreau5cbea6f2005-12-17 12:48:26 +01001765/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001766 * may be only moved or left where it was, depending on its timing requirements.
1767 * <task> is returned.
1768 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001769struct task *task_queue(struct task *task) {
1770 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001771 struct task *start_from;
1772
willy tarreau5e698ef2006-05-02 14:51:00 +02001773 /* This is a very dirty hack to queue non-expirable tasks in another queue
1774 * in order to avoid pulluting the tail of the standard queue. This will go
1775 * away with the new O(log(n)) scheduler anyway.
1776 */
1777 if (tv_iseternity(&task->expire)) {
1778 /* if the task was queued in the standard wait queue, we must dequeue it */
1779 if (task->prev) {
1780 if (task->wq == LIST_HEAD(wait_queue[1]))
1781 return task;
1782 else {
1783 task_delete(task);
1784 task->prev = NULL;
1785 }
1786 }
1787 list = task->wq = LIST_HEAD(wait_queue[1]);
1788 } else {
1789 /* if the task was queued in the eternity queue, we must dequeue it */
1790 if (task->prev && (task->wq == LIST_HEAD(wait_queue[1]))) {
1791 task_delete(task);
1792 task->prev = NULL;
1793 list = task->wq = LIST_HEAD(wait_queue[0]);
1794 }
1795 }
1796
1797 /* next, test if the task was already in a list */
willy tarreau0f7af912005-12-17 12:21:26 +01001798 if (task->prev == NULL) {
1799 // start_from = list;
1800 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001801#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001802 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001803#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001804 /* insert the unlinked <task> into the list, searching back from the last entry */
1805 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1806 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001807#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001808 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001809#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001810 }
1811
1812 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1813 // start_from = start_from->next;
1814 // stats_tsk_nsrch++;
1815 // }
1816 }
1817 else if (task->prev == list ||
1818 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1819 start_from = task->next;
1820 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001821#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001822 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001823#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001824 return task; /* it's already in the right place */
1825 }
1826
willy tarreau750a4722005-12-17 13:21:24 +01001827#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001828 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001829#endif
1830
1831 /* if the task is not at the right place, there's little chance that
1832 * it has only shifted a bit, and it will nearly always be queued
1833 * at the end of the list because of constant timeouts
1834 * (observed in real case).
1835 */
1836#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1837 start_from = list->prev; /* assume we'll queue to the end of the list */
1838 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1839 start_from = start_from->prev;
1840#if STATTIME > 0
1841 stats_tsk_lsrch++;
1842#endif
1843 }
1844#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001845 /* insert the unlinked <task> into the list, searching after position <start_from> */
1846 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1847 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001848#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001849 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001850#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001851 }
willy tarreau750a4722005-12-17 13:21:24 +01001852#endif /* WE_REALLY_... */
1853
willy tarreau0f7af912005-12-17 12:21:26 +01001854 /* we need to unlink it now */
1855 task_delete(task);
1856 }
1857 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001858#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001859 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001860#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001861#ifdef LEFT_TO_TOP /* not very good */
1862 start_from = list;
1863 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1864 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001865#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001866 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001867#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001868 }
1869#else
1870 start_from = task->prev->prev; /* valid because of the previous test above */
1871 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1872 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001873#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001874 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001875#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001876 }
1877#endif
1878 /* we need to unlink it now */
1879 task_delete(task);
1880 }
1881 task->prev = start_from;
1882 task->next = start_from->next;
1883 task->next->prev = task;
1884 start_from->next = task;
1885 return task;
1886}
1887
1888
1889/*********************************************************************/
willy tarreau18a957c2006-04-12 19:26:23 +02001890/* pending connections queues **************************************/
1891/*********************************************************************/
1892
1893/*
willy tarreaudfece232006-05-02 00:19:57 +02001894 * Detaches pending connection <p>, decreases the pending count, and frees
1895 * the pending connection. The connection might have been queued to a specific
1896 * server as well as to the proxy. The session also gets marked unqueued.
willy tarreau18a957c2006-04-12 19:26:23 +02001897 */
willy tarreaudfece232006-05-02 00:19:57 +02001898static void pendconn_free(struct pendconn *p) {
1899 LIST_DEL(&p->list);
1900 p->sess->pend_pos = NULL;
1901 if (p->srv)
1902 p->srv->nbpend--;
1903 else
1904 p->sess->proxy->nbpend--;
willy tarreauf32f5242006-05-02 22:54:52 +02001905 p->sess->proxy->totpend--;
willy tarreaudfece232006-05-02 00:19:57 +02001906 pool_free(pendconn, p);
1907}
1908
1909/* Returns the first pending connection for server <s>, which may be NULL if
1910 * nothing is pending.
1911 */
1912static inline struct pendconn *pendconn_from_srv(struct server *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001913 if (!s->nbpend)
1914 return NULL;
1915
1916 return LIST_ELEM(s->pendconns.n, struct pendconn *, list);
1917}
1918
willy tarreaudfece232006-05-02 00:19:57 +02001919/* Returns the first pending connection for proxy <px>, which may be NULL if
1920 * nothing is pending.
willy tarreau18a957c2006-04-12 19:26:23 +02001921 */
willy tarreaudfece232006-05-02 00:19:57 +02001922static inline struct pendconn *pendconn_from_px(struct proxy *px) {
1923 if (!px->nbpend)
1924 return NULL;
1925
1926 return LIST_ELEM(px->pendconns.n, struct pendconn *, list);
willy tarreau18a957c2006-04-12 19:26:23 +02001927}
1928
willy tarreaubc2eda62006-05-04 15:16:23 +02001929/* Detaches the next pending connection from either a server or a proxy, and
1930 * returns its associated session. If no pending connection is found, NULL is
1931 * returned. Note that neither <srv> nor <px> can be NULL.
willy tarreau18a957c2006-04-12 19:26:23 +02001932 */
willy tarreaubc2eda62006-05-04 15:16:23 +02001933static struct session *pendconn_get_next_sess(struct server *srv, struct proxy *px) {
willy tarreau18a957c2006-04-12 19:26:23 +02001934 struct pendconn *p;
1935 struct session *sess;
1936
willy tarreaubc2eda62006-05-04 15:16:23 +02001937 p = pendconn_from_srv(srv);
willy tarreaudfece232006-05-02 00:19:57 +02001938 if (!p) {
willy tarreaubc2eda62006-05-04 15:16:23 +02001939 p = pendconn_from_px(px);
willy tarreaudfece232006-05-02 00:19:57 +02001940 if (!p)
1941 return NULL;
willy tarreaubc2eda62006-05-04 15:16:23 +02001942 p->sess->srv = srv;
willy tarreaudfece232006-05-02 00:19:57 +02001943 }
willy tarreau18a957c2006-04-12 19:26:23 +02001944 sess = p->sess;
1945 pendconn_free(p);
1946 return sess;
1947}
1948
willy tarreaudfece232006-05-02 00:19:57 +02001949/* Adds the session <sess> to the pending connection list of server <sess>->srv
1950 * or to the one of <sess>->proxy if srv is NULL. All counters and back pointers
1951 * are updated accordingly. Returns NULL if no memory is available, otherwise the
1952 * pendconn itself.
willy tarreau18a957c2006-04-12 19:26:23 +02001953 */
willy tarreaudfece232006-05-02 00:19:57 +02001954static struct pendconn *pendconn_add(struct session *sess) {
willy tarreau18a957c2006-04-12 19:26:23 +02001955 struct pendconn *p;
1956
1957 p = pool_alloc(pendconn);
1958 if (!p)
1959 return NULL;
1960
willy tarreau18a957c2006-04-12 19:26:23 +02001961 sess->pend_pos = p;
willy tarreaudfece232006-05-02 00:19:57 +02001962 p->sess = sess;
1963 p->srv = sess->srv;
1964 if (sess->srv) {
1965 LIST_ADDQ(&sess->srv->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001966 sess->logs.srv_queue_size += sess->srv->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001967 sess->srv->nbpend++;
willy tarreaucb406512006-05-18 00:52:35 +02001968 if (sess->srv->nbpend > sess->srv->nbpend_max)
1969 sess->srv->nbpend_max = sess->srv->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001970 } else {
1971 LIST_ADDQ(&sess->proxy->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001972 sess->logs.prx_queue_size += sess->proxy->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001973 sess->proxy->nbpend++;
willy tarreaucb406512006-05-18 00:52:35 +02001974 if (sess->proxy->nbpend > sess->proxy->nbpend_max)
1975 sess->proxy->nbpend_max = sess->proxy->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001976 }
willy tarreauf32f5242006-05-02 22:54:52 +02001977 sess->proxy->totpend++;
willy tarreau18a957c2006-04-12 19:26:23 +02001978 return p;
1979}
1980
willy tarreau59a6cc22006-05-12 01:29:08 +02001981/* returns 0 if nothing has to be done for server <s> regarding queued connections,
1982 * and non-zero otherwise. Suited for and if/else usage.
1983 */
1984static inline int may_dequeue_tasks(struct server *s, struct proxy *p) {
1985 return (s && (s->nbpend || p->nbpend) &&
1986 s->maxconn && s->cur_sess < s->maxconn && s->queue_mgt);
1987}
1988
1989
1990
willy tarreau18a957c2006-04-12 19:26:23 +02001991/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +01001992/* more specific functions ***************************************/
1993/*********************************************************************/
1994
1995/* some prototypes */
1996static int maintain_proxies(void);
1997
willy tarreaub952e1d2005-12-18 01:31:20 +01001998/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001999 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
2000 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01002001static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01002002#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002003 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
2004#else
willy tarreaua1598082005-12-17 13:08:06 +01002005#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002006 return getsockname(fd, (struct sockaddr *)sa, salen);
2007#else
2008 return -1;
2009#endif
2010#endif
2011}
2012
2013/*
2014 * frees the context associated to a session. It must have been removed first.
2015 */
willy tarreaudfece232006-05-02 00:19:57 +02002016static void session_free(struct session *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02002017 if (s->pend_pos)
2018 pendconn_free(s->pend_pos);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002019 if (s->req)
2020 pool_free(buffer, s->req);
2021 if (s->rep)
2022 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01002023
2024 if (s->rsp_cap != NULL) {
2025 struct cap_hdr *h;
2026 for (h = s->proxy->rsp_cap; h; h = h->next) {
2027 if (s->rsp_cap[h->index] != NULL)
2028 pool_free_to(h->pool, s->rsp_cap[h->index]);
2029 }
2030 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
2031 }
2032 if (s->req_cap != NULL) {
2033 struct cap_hdr *h;
2034 for (h = s->proxy->req_cap; h; h = h->next) {
2035 if (s->req_cap[h->index] != NULL)
2036 pool_free_to(h->pool, s->req_cap[h->index]);
2037 }
2038 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
2039 }
2040
willy tarreaua1598082005-12-17 13:08:06 +01002041 if (s->logs.uri)
2042 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01002043 if (s->logs.cli_cookie)
2044 pool_free(capture, s->logs.cli_cookie);
2045 if (s->logs.srv_cookie)
2046 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01002047
willy tarreau5cbea6f2005-12-17 12:48:26 +01002048 pool_free(session, s);
2049}
2050
willy tarreau0f7af912005-12-17 12:21:26 +01002051
2052/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01002053 * This function recounts the number of usable active and backup servers for
2054 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002055 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01002056 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002057static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002058 struct server *srv;
2059
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002060 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002061 for (srv = px->srv; srv != NULL; srv = srv->next) {
2062 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002063 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002064 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002065 px->tot_wbck += srv->eweight + 1;
2066 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002067 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002068 px->tot_wact += srv->eweight + 1;
2069 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01002070 }
2071 }
2072}
2073
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002074/* This function recomputes the server map for proxy px. It
2075 * relies on px->tot_wact and px->tot_wbck, so it must be
2076 * called after recount_servers(). It also expects px->srv_map
2077 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01002078 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002079static void recalc_server_map(struct proxy *px) {
2080 int o, tot, flag;
2081 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01002082
willy tarreau4c8c2b52006-03-24 19:36:41 +01002083 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002084 flag = SRV_RUNNING;
2085 tot = px->tot_wact;
2086 } else if (px->srv_bck) {
2087 flag = SRV_RUNNING | SRV_BACKUP;
2088 if (px->options & PR_O_USE_ALL_BK)
2089 tot = px->tot_wbck;
2090 else
2091 tot = 1; /* the first server is enough */
2092 } else {
2093 px->srv_map_sz = 0;
2094 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002095 }
Willy TARREAU3481c462006-03-01 22:37:57 +01002096
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002097 /* this algorithm gives priority to the first server, which means that
2098 * it will respect the declaration order for equivalent weights, and
2099 * that whatever the weights, the first server called will always be
2100 * the first declard. This is an important asumption for the backup
2101 * case, where we want the first server only.
2102 */
2103 for (cur = px->srv; cur; cur = cur->next)
2104 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002105
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002106 for (o = 0; o < tot; o++) {
2107 int max = 0;
2108 best = NULL;
2109 for (cur = px->srv; cur; cur = cur->next) {
2110 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
2111 int v;
2112
2113 /* If we are forced to return only one server, we don't want to
2114 * go further, because we would return the wrong one due to
2115 * divide overflow.
2116 */
2117 if (tot == 1) {
2118 best = cur;
2119 break;
2120 }
2121
2122 cur->wscore += cur->eweight + 1;
2123 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
2124 if (best == NULL || v > max) {
2125 max = v;
2126 best = cur;
2127 }
2128 }
2129 }
2130 px->srv_map[o] = best;
2131 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002132 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002133 px->srv_map_sz = tot;
2134}
Willy TARREAU3481c462006-03-01 22:37:57 +01002135
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002136/*
willy tarreau898db9d2006-04-12 20:29:08 +02002137 * This function tries to find a running server with free connection slots for
2138 * the proxy <px> following the round-robin method.
2139 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2140 * to point to the next server. If no valid server is found, NULL is returned.
2141 */
2142static inline struct server *get_server_rr_with_conns(struct proxy *px) {
2143 int newidx;
2144 struct server *srv;
2145
2146 if (px->srv_map_sz == 0)
2147 return NULL;
2148
2149 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2150 px->srv_rr_idx = 0;
2151 newidx = px->srv_rr_idx;
2152
2153 do {
2154 srv = px->srv_map[newidx++];
2155 if (!srv->maxconn || srv->cur_sess < srv->maxconn) {
2156 px->srv_rr_idx = newidx;
2157 return srv;
2158 }
2159 if (newidx == px->srv_map_sz)
2160 newidx = 0;
2161 } while (newidx != px->srv_rr_idx);
2162
2163 return NULL;
2164}
2165
2166
2167/*
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002168 * This function tries to find a running server for the proxy <px> following
willy tarreau898db9d2006-04-12 20:29:08 +02002169 * the round-robin method.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002170 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2171 * to point to the next server. If no valid server is found, NULL is returned.
2172 */
2173static inline struct server *get_server_rr(struct proxy *px) {
2174 if (px->srv_map_sz == 0)
2175 return NULL;
2176
2177 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2178 px->srv_rr_idx = 0;
2179 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01002180}
2181
willy tarreau62084d42006-03-24 18:57:41 +01002182
2183/*
willy tarreau1a3442d2006-03-24 21:03:20 +01002184 * This function tries to find a running server for the proxy <px> following
2185 * the source hash method. Depending on the number of active/backup servers,
2186 * it will either look for active servers, or for backup servers.
2187 * If any server is found, it will be returned. If no valid server is found,
2188 * NULL is returned.
2189 */
2190static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002191 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01002192
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002193 if (px->srv_map_sz == 0)
2194 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01002195
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002196 l = h = 0;
willy tarreaucd655352006-04-29 12:11:46 +02002197 if (px->srv_act > 1 || (px->srv_act == 0 && px->srv_bck > 1)) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002198 while ((l + sizeof (int)) <= len) {
2199 h ^= ntohl(*(unsigned int *)(&addr[l]));
2200 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01002201 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002202 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01002203 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002204 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01002205}
2206
2207
2208/*
willy tarreaudfece232006-05-02 00:19:57 +02002209 * This function marks the session as 'assigned' in direct or dispatch modes,
2210 * or tries to assign one in balance mode, according to the algorithm. It does
2211 * nothing if the session had already been assigned a server.
2212 *
2213 * It may return :
willy tarreau000375f2006-05-09 23:15:58 +02002214 * SRV_STATUS_OK if everything is OK. s->srv will be valid.
2215 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
2216 * SRV_STATUS_FULL if all servers are saturated. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002217 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2218 *
2219 * Upon successful return, the session flag SN_ASSIGNED to indicate that it does
2220 * not need to be called anymore. This usually means that s->srv can be trusted
2221 * in balance and direct modes. This flag is not cleared, so it's to the caller
2222 * to clear it if required (eg: redispatch).
2223 *
willy tarreau0f7af912005-12-17 12:21:26 +01002224 */
willy tarreau0f7af912005-12-17 12:21:26 +01002225
willy tarreaudfece232006-05-02 00:19:57 +02002226int assign_server(struct session *s) {
willy tarreau12350152005-12-18 01:03:27 +01002227#ifdef DEBUG_FULL
willy tarreaudfece232006-05-02 00:19:57 +02002228 fprintf(stderr,"assign_server : s=%p\n",s);
willy tarreau12350152005-12-18 01:03:27 +01002229#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002230
willy tarreaudfece232006-05-02 00:19:57 +02002231 if (s->pend_pos)
2232 return SRV_STATUS_INTERNAL;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002233
willy tarreaudfece232006-05-02 00:19:57 +02002234 if (!(s->flags & SN_ASSIGNED)) {
2235 if ((s->proxy->options & PR_O_BALANCE) && !(s->flags & SN_DIRECT)) {
2236 if (!s->proxy->srv_act && !s->proxy->srv_bck)
2237 return SRV_STATUS_NOSRV;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002238
willy tarreaudfece232006-05-02 00:19:57 +02002239 if (s->proxy->options & PR_O_BALANCE_RR) {
2240 s->srv = get_server_rr_with_conns(s->proxy);
2241 if (!s->srv)
2242 return SRV_STATUS_FULL;
2243 }
2244 else if (s->proxy->options & PR_O_BALANCE_SH) {
2245 int len;
2246
2247 if (s->cli_addr.ss_family == AF_INET)
2248 len = 4;
2249 else if (s->cli_addr.ss_family == AF_INET6)
2250 len = 16;
2251 else /* unknown IP family */
2252 return SRV_STATUS_INTERNAL;
2253
2254 s->srv = get_server_sh(s->proxy,
2255 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2256 len);
2257 }
2258 else /* unknown balancing algorithm */
2259 return SRV_STATUS_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002260 }
willy tarreaudfece232006-05-02 00:19:57 +02002261 s->flags |= SN_ASSIGNED;
2262 }
2263 return SRV_STATUS_OK;
2264}
willy tarreau1a3442d2006-03-24 21:03:20 +01002265
willy tarreaudfece232006-05-02 00:19:57 +02002266/*
2267 * This function assigns a server address to a session, and sets SN_ADDR_SET.
2268 * The address is taken from the currently assigned server, or from the
2269 * dispatch or transparent address.
2270 *
2271 * It may return :
2272 * SRV_STATUS_OK if everything is OK.
2273 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2274 *
2275 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
2276 * not cleared, so it's to the caller to clear it if required.
2277 *
2278 */
2279int assign_server_address(struct session *s) {
2280#ifdef DEBUG_FULL
2281 fprintf(stderr,"assign_server_address : s=%p\n",s);
2282#endif
2283
2284 if (s->flags & SN_DIRECT || s->proxy->options & PR_O_BALANCE) {
2285 /* A server is necessarily known for this session */
2286 if (!(s->flags & SN_ASSIGNED))
2287 return SRV_STATUS_INTERNAL;
2288
2289 s->srv_addr = s->srv->addr;
willy tarreau1a3442d2006-03-24 21:03:20 +01002290
willy tarreaudfece232006-05-02 00:19:57 +02002291 /* if this server remaps proxied ports, we'll use
2292 * the port the client connected to with an offset. */
2293 if (s->srv->state & SRV_MAPPORTS) {
2294 struct sockaddr_in sockname;
2295 socklen_t namelen = sizeof(sockname);
2296
2297 if (!(s->proxy->options & PR_O_TRANSP) ||
2298 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2299 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2300 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
willy tarreau1a3442d2006-03-24 21:03:20 +01002301 }
willy tarreau0f7af912005-12-17 12:21:26 +01002302 }
willy tarreaua1598082005-12-17 13:08:06 +01002303 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002304 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002305 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002306 }
2307 else if (s->proxy->options & PR_O_TRANSP) {
2308 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002309 socklen_t salen = sizeof(s->srv_addr);
2310
willy tarreau5cbea6f2005-12-17 12:48:26 +01002311 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2312 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaudfece232006-05-02 00:19:57 +02002313 return SRV_STATUS_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002314 }
2315 }
willy tarreau0f7af912005-12-17 12:21:26 +01002316
willy tarreaudfece232006-05-02 00:19:57 +02002317 s->flags |= SN_ADDR_SET;
2318 return SRV_STATUS_OK;
2319}
willy tarreaua41a8b42005-12-17 14:02:24 +01002320
willy tarreaudfece232006-05-02 00:19:57 +02002321/* This function assigns a server to session <s> if required, and can add the
2322 * connection to either the assigned server's queue or to the proxy's queue.
2323 *
2324 * Returns :
2325 *
2326 * SRV_STATUS_OK if everything is OK.
willy tarreau000375f2006-05-09 23:15:58 +02002327 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002328 * SRV_STATUS_QUEUED if the connection has been queued.
2329 * SRV_STATUS_FULL if the server(s) is/are saturated and the
2330 * connection could not be queued.
2331 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2332 *
2333 */
2334int assign_server_and_queue(struct session *s) {
2335 struct pendconn *p;
2336 int err;
2337
2338 if (s->pend_pos)
2339 return SRV_STATUS_INTERNAL;
2340
2341 if (s->flags & SN_ASSIGNED) {
2342 /* a server does not need to be assigned, perhaps because we're in
2343 * direct mode, or in dispatch or transparent modes where the server
2344 * is not needed.
2345 */
2346 if (s->srv &&
2347 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2348 p = pendconn_add(s);
2349 if (p)
2350 return SRV_STATUS_QUEUED;
2351 else
2352 return SRV_STATUS_FULL;
2353 }
2354 return SRV_STATUS_OK;
2355 }
2356
2357 /* a server needs to be assigned */
2358 err = assign_server(s);
2359 switch (err) {
2360 case SRV_STATUS_OK:
2361 /* in balance mode, we might have servers with connection limits */
2362 if (s->srv != NULL &&
2363 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2364 p = pendconn_add(s);
2365 if (p)
2366 return SRV_STATUS_QUEUED;
2367 else
2368 return SRV_STATUS_FULL;
2369 }
2370 return SRV_STATUS_OK;
2371
2372 case SRV_STATUS_FULL:
2373 /* queue this session into the proxy's queue */
2374 p = pendconn_add(s);
2375 if (p)
2376 return SRV_STATUS_QUEUED;
2377 else
2378 return SRV_STATUS_FULL;
2379
2380 case SRV_STATUS_NOSRV:
2381 case SRV_STATUS_INTERNAL:
2382 return err;
2383 default:
2384 return SRV_STATUS_INTERNAL;
willy tarreaua41a8b42005-12-17 14:02:24 +01002385 }
willy tarreaudfece232006-05-02 00:19:57 +02002386}
2387
2388
2389/*
2390 * This function initiates a connection to the server assigned to this session
2391 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
2392 * It can return one of :
2393 * - SN_ERR_NONE if everything's OK
2394 * - SN_ERR_SRVTO if there are no more servers
2395 * - SN_ERR_SRVCL if the connection was refused by the server
2396 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
2397 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
2398 * - SN_ERR_INTERNAL for any other purely internal errors
2399 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
2400 */
2401int connect_server(struct session *s) {
2402 int fd, err;
2403
2404 if (!(s->flags & SN_ADDR_SET)) {
2405 err = assign_server_address(s);
2406 if (err != SRV_STATUS_OK)
2407 return SN_ERR_INTERNAL;
2408 }
willy tarreaua41a8b42005-12-17 14:02:24 +01002409
willy tarreau0f7af912005-12-17 12:21:26 +01002410 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002411 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002412
2413 if (errno == ENFILE)
2414 send_log(s->proxy, LOG_EMERG,
2415 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2416 s->proxy->id, maxfd);
2417 else if (errno == EMFILE)
2418 send_log(s->proxy, LOG_EMERG,
2419 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2420 s->proxy->id, maxfd);
2421 else if (errno == ENOBUFS || errno == ENOMEM)
2422 send_log(s->proxy, LOG_EMERG,
2423 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2424 s->proxy->id, maxfd);
2425 /* this is a resource error */
2426 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002427 }
2428
willy tarreau9fe663a2005-12-17 13:02:59 +01002429 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002430 /* do not log anything there, it's a normal condition when this option
2431 * is used to serialize connections to a server !
2432 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002433 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2434 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002435 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002436 }
2437
willy tarreau0f7af912005-12-17 12:21:26 +01002438 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2439 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002440 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002441 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002442 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002443 }
2444
willy tarreaub952e1d2005-12-18 01:31:20 +01002445 if (s->proxy->options & PR_O_TCP_SRV_KA)
2446 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2447
willy tarreau0174f312005-12-18 01:02:42 +01002448 /* allow specific binding :
2449 * - server-specific at first
2450 * - proxy-specific next
2451 */
2452 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2453 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2454 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2455 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2456 s->proxy->id, s->srv->id);
2457 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002458 send_log(s->proxy, LOG_EMERG,
2459 "Cannot bind to source address before connect() for server %s/%s.\n",
2460 s->proxy->id, s->srv->id);
2461 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002462 }
2463 }
2464 else if (s->proxy->options & PR_O_BIND_SRC) {
2465 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2466 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2467 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2468 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002469 send_log(s->proxy, LOG_EMERG,
2470 "Cannot bind to source address before connect() for server %s/%s.\n",
2471 s->proxy->id, s->srv->id);
2472 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002473 }
willy tarreaua1598082005-12-17 13:08:06 +01002474 }
2475
willy tarreaub1285d52005-12-18 01:20:14 +01002476 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2477 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2478
2479 if (errno == EAGAIN || errno == EADDRINUSE) {
2480 char *msg;
2481 if (errno == EAGAIN) /* no free ports left, try again later */
2482 msg = "no free ports";
2483 else
2484 msg = "local address already in use";
2485
2486 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002487 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002488 send_log(s->proxy, LOG_EMERG,
2489 "Connect() failed for server %s/%s: %s.\n",
2490 s->proxy->id, s->srv->id, msg);
2491 return SN_ERR_RESOURCE;
2492 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002493 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002494 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002495 return SN_ERR_SRVTO;
2496 } else {
2497 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002498 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002499 close(fd);
2500 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002501 }
2502 }
2503
willy tarreau5cbea6f2005-12-17 12:48:26 +01002504 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002505 fdtab[fd].read = &event_srv_read;
2506 fdtab[fd].write = &event_srv_write;
2507 fdtab[fd].state = FD_STCONN; /* connection in progress */
2508
2509 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002510#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2511 if (PrevReadEvent) {
2512 assert(!(FD_ISSET(fd, PrevReadEvent)));
2513 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2514 }
2515#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002516
2517 fd_insert(fd);
willy tarreaucb406512006-05-18 00:52:35 +02002518 if (s->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02002519 s->srv->cur_sess++;
willy tarreaucb406512006-05-18 00:52:35 +02002520 if (s->srv->cur_sess > s->srv->cur_sess_max)
2521 s->srv->cur_sess_max = s->srv->cur_sess;
2522 }
willy tarreau0f7af912005-12-17 12:21:26 +01002523
2524 if (s->proxy->contimeout)
2525 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2526 else
2527 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002528 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002529}
2530
2531/*
2532 * this function is called on a read event from a client socket.
2533 * It returns 0.
2534 */
2535int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002536 struct task *t = fdtab[fd].owner;
2537 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002538 struct buffer *b = s->req;
2539 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002540
willy tarreau12350152005-12-18 01:03:27 +01002541#ifdef DEBUG_FULL
2542 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2543#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002544
willy tarreau0f7af912005-12-17 12:21:26 +01002545 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002546#ifdef FILL_BUFFERS
2547 while (1)
2548#else
2549 do
2550#endif
2551 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002552 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2553 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002554 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002555 }
2556 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002557 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002558 }
2559 else {
2560 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002561 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2562 * since it means that the rewrite protection has been removed. This
2563 * implies that the if statement can be removed.
2564 */
2565 if (max > b->rlim - b->data)
2566 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002567 }
2568
2569 if (max == 0) { /* not anymore room to store data */
2570 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002571 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002572 }
2573
willy tarreau3242e862005-12-17 12:27:53 +01002574#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002575 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002576 int skerr;
2577 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002578
willy tarreau5cbea6f2005-12-17 12:48:26 +01002579 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2580 if (skerr)
2581 ret = -1;
2582 else
2583 ret = recv(fd, b->r, max, 0);
2584 }
willy tarreau3242e862005-12-17 12:27:53 +01002585#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002586 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002587#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002588 if (ret > 0) {
2589 b->r += ret;
2590 b->l += ret;
2591 s->res_cr = RES_DATA;
2592
2593 if (b->r == b->data + BUFSIZE) {
2594 b->r = b->data; /* wrap around the buffer */
2595 }
willy tarreaua1598082005-12-17 13:08:06 +01002596
2597 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002598 /* we hope to read more data or to get a close on next round */
2599 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002600 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002601 else if (ret == 0) {
2602 s->res_cr = RES_NULL;
2603 break;
2604 }
2605 else if (errno == EAGAIN) {/* ignore EAGAIN */
2606 break;
2607 }
2608 else {
2609 s->res_cr = RES_ERROR;
2610 fdtab[fd].state = FD_STERROR;
2611 break;
2612 }
2613 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002614#ifndef FILL_BUFFERS
2615 while (0);
2616#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002617 }
2618 else {
2619 s->res_cr = RES_ERROR;
2620 fdtab[fd].state = FD_STERROR;
2621 }
2622
willy tarreau5cbea6f2005-12-17 12:48:26 +01002623 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002624 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002625 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2626 else
2627 tv_eternity(&s->crexpire);
2628
2629 task_wakeup(&rq, t);
2630 }
willy tarreau0f7af912005-12-17 12:21:26 +01002631
willy tarreau0f7af912005-12-17 12:21:26 +01002632 return 0;
2633}
2634
2635
2636/*
2637 * this function is called on a read event from a server socket.
2638 * It returns 0.
2639 */
2640int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002641 struct task *t = fdtab[fd].owner;
2642 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002643 struct buffer *b = s->rep;
2644 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002645
willy tarreau12350152005-12-18 01:03:27 +01002646#ifdef DEBUG_FULL
2647 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2648#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002649
willy tarreau0f7af912005-12-17 12:21:26 +01002650 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002651#ifdef FILL_BUFFERS
2652 while (1)
2653#else
2654 do
2655#endif
2656 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002657 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2658 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002659 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002660 }
2661 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002662 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002663 }
2664 else {
2665 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002666 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2667 * since it means that the rewrite protection has been removed. This
2668 * implies that the if statement can be removed.
2669 */
2670 if (max > b->rlim - b->data)
2671 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002672 }
2673
2674 if (max == 0) { /* not anymore room to store data */
2675 FD_CLR(fd, StaticReadEvent);
2676 break;
2677 }
2678
willy tarreau3242e862005-12-17 12:27:53 +01002679#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002680 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002681 int skerr;
2682 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002683
willy tarreau5cbea6f2005-12-17 12:48:26 +01002684 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2685 if (skerr)
2686 ret = -1;
2687 else
2688 ret = recv(fd, b->r, max, 0);
2689 }
willy tarreau3242e862005-12-17 12:27:53 +01002690#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002691 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002692#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002693 if (ret > 0) {
2694 b->r += ret;
2695 b->l += ret;
2696 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002697
willy tarreau5cbea6f2005-12-17 12:48:26 +01002698 if (b->r == b->data + BUFSIZE) {
2699 b->r = b->data; /* wrap around the buffer */
2700 }
willy tarreaua1598082005-12-17 13:08:06 +01002701
2702 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002703 /* we hope to read more data or to get a close on next round */
2704 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002705 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002706 else if (ret == 0) {
2707 s->res_sr = RES_NULL;
2708 break;
2709 }
2710 else if (errno == EAGAIN) {/* ignore EAGAIN */
2711 break;
2712 }
2713 else {
2714 s->res_sr = RES_ERROR;
2715 fdtab[fd].state = FD_STERROR;
2716 break;
2717 }
2718 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002719#ifndef FILL_BUFFERS
2720 while (0);
2721#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002722 }
2723 else {
2724 s->res_sr = RES_ERROR;
2725 fdtab[fd].state = FD_STERROR;
2726 }
2727
willy tarreau5cbea6f2005-12-17 12:48:26 +01002728 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002729 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002730 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2731 else
2732 tv_eternity(&s->srexpire);
2733
2734 task_wakeup(&rq, t);
2735 }
willy tarreau0f7af912005-12-17 12:21:26 +01002736
willy tarreau0f7af912005-12-17 12:21:26 +01002737 return 0;
2738}
2739
2740/*
2741 * this function is called on a write event from a client socket.
2742 * It returns 0.
2743 */
2744int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002745 struct task *t = fdtab[fd].owner;
2746 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002747 struct buffer *b = s->rep;
2748 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002749
willy tarreau12350152005-12-18 01:03:27 +01002750#ifdef DEBUG_FULL
2751 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2752#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002753
2754 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002755 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002756 // max = BUFSIZE; BUG !!!!
2757 max = 0;
2758 }
2759 else if (b->r > b->w) {
2760 max = b->r - b->w;
2761 }
2762 else
2763 max = b->data + BUFSIZE - b->w;
2764
willy tarreau0f7af912005-12-17 12:21:26 +01002765 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002766 if (max == 0) {
2767 s->res_cw = RES_NULL;
2768 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002769 tv_eternity(&s->cwexpire);
2770 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002771 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002772 }
2773
willy tarreau3242e862005-12-17 12:27:53 +01002774#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002775 {
2776 int skerr;
2777 socklen_t lskerr = sizeof(skerr);
2778
2779 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2780 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002781 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002782 else
willy tarreau3242e862005-12-17 12:27:53 +01002783 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002784 }
willy tarreau3242e862005-12-17 12:27:53 +01002785#else
willy tarreau0f7af912005-12-17 12:21:26 +01002786 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002787#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002788
2789 if (ret > 0) {
2790 b->l -= ret;
2791 b->w += ret;
2792
2793 s->res_cw = RES_DATA;
2794
2795 if (b->w == b->data + BUFSIZE) {
2796 b->w = b->data; /* wrap around the buffer */
2797 }
2798 }
2799 else if (ret == 0) {
2800 /* nothing written, just make as if we were never called */
2801// s->res_cw = RES_NULL;
2802 return 0;
2803 }
2804 else if (errno == EAGAIN) /* ignore EAGAIN */
2805 return 0;
2806 else {
2807 s->res_cw = RES_ERROR;
2808 fdtab[fd].state = FD_STERROR;
2809 }
2810 }
2811 else {
2812 s->res_cw = RES_ERROR;
2813 fdtab[fd].state = FD_STERROR;
2814 }
2815
willy tarreaub1ff9db2005-12-17 13:51:03 +01002816 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002817 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002818 /* FIXME: to prevent the client from expiring read timeouts during writes,
2819 * we refresh it. A solution would be to merge read+write timeouts into a
2820 * unique one, although that needs some study particularly on full-duplex
2821 * TCP connections. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002822 s->crexpire = s->cwexpire;
2823 }
willy tarreau0f7af912005-12-17 12:21:26 +01002824 else
2825 tv_eternity(&s->cwexpire);
2826
willy tarreau5cbea6f2005-12-17 12:48:26 +01002827 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002828 return 0;
2829}
2830
2831
2832/*
2833 * this function is called on a write event from a server socket.
2834 * It returns 0.
2835 */
2836int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002837 struct task *t = fdtab[fd].owner;
2838 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002839 struct buffer *b = s->req;
2840 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002841
willy tarreau12350152005-12-18 01:03:27 +01002842#ifdef DEBUG_FULL
2843 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2844#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002845
2846 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002847 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002848 // max = BUFSIZE; BUG !!!!
2849 max = 0;
2850 }
2851 else if (b->r > b->w) {
2852 max = b->r - b->w;
2853 }
2854 else
2855 max = b->data + BUFSIZE - b->w;
2856
willy tarreau0f7af912005-12-17 12:21:26 +01002857 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002858 if (max == 0) {
2859 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002860 if (s->srv_state == SV_STCONN) {
2861 int skerr;
2862 socklen_t lskerr = sizeof(skerr);
2863 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2864 if (skerr) {
2865 s->res_sw = RES_ERROR;
2866 fdtab[fd].state = FD_STERROR;
2867 task_wakeup(&rq, t);
2868 tv_eternity(&s->swexpire);
2869 FD_CLR(fd, StaticWriteEvent);
2870 return 0;
2871 }
2872 }
2873
willy tarreau0f7af912005-12-17 12:21:26 +01002874 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002875 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002876 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002877 tv_eternity(&s->swexpire);
2878 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002879 return 0;
2880 }
2881
willy tarreau3242e862005-12-17 12:27:53 +01002882#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002883 {
2884 int skerr;
2885 socklen_t lskerr = sizeof(skerr);
2886 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2887 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002888 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002889 else
willy tarreau3242e862005-12-17 12:27:53 +01002890 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002891 }
willy tarreau3242e862005-12-17 12:27:53 +01002892#else
willy tarreau0f7af912005-12-17 12:21:26 +01002893 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002894#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002895 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002896 if (ret > 0) {
2897 b->l -= ret;
2898 b->w += ret;
2899
2900 s->res_sw = RES_DATA;
2901
2902 if (b->w == b->data + BUFSIZE) {
2903 b->w = b->data; /* wrap around the buffer */
2904 }
2905 }
2906 else if (ret == 0) {
2907 /* nothing written, just make as if we were never called */
2908 // s->res_sw = RES_NULL;
2909 return 0;
2910 }
2911 else if (errno == EAGAIN) /* ignore EAGAIN */
2912 return 0;
2913 else {
2914 s->res_sw = RES_ERROR;
2915 fdtab[fd].state = FD_STERROR;
2916 }
2917 }
2918 else {
2919 s->res_sw = RES_ERROR;
2920 fdtab[fd].state = FD_STERROR;
2921 }
2922
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002923 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2924 * otherwise it could loop indefinitely !
2925 */
2926 if (s->srv_state != SV_STCONN) {
2927 if (s->proxy->srvtimeout) {
2928 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002929 /* FIXME: to prevent the server from expiring read timeouts during writes,
2930 * we refresh it. A solution would be to merge read+write+connect timeouts
2931 * into a unique one since we don't mind expiring on read or write, and none
2932 * of them is enabled while waiting for connect(), although that needs some
2933 * study particularly on full-duplex TCP connections. */
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002934 s->srexpire = s->swexpire;
2935 }
2936 else
2937 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002938 }
willy tarreau0f7af912005-12-17 12:21:26 +01002939
willy tarreau5cbea6f2005-12-17 12:48:26 +01002940 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002941 return 0;
2942}
2943
2944
willy tarreaue0331262006-05-15 03:02:46 +02002945/* returns 1 if the buffer is empty, 0 otherwise */
2946static inline int buffer_isempty(struct buffer *buf) {
2947 return buf->l == 0;
2948}
2949
2950
2951/* returns 1 if the buffer is full, 0 otherwise */
2952static inline int buffer_isfull(struct buffer *buf) {
2953 return buf->l == BUFSIZE;
2954}
2955
2956
2957/* flushes any content from buffer <buf> */
2958void buffer_flush(struct buffer *buf) {
2959 buf->r = buf->h = buf->lr = buf->w = buf->data;
2960 buf->l = 0;
2961}
2962
2963
2964/* returns the maximum number of bytes writable at once in this buffer */
2965int buffer_max(struct buffer *buf) {
willy tarreaucb406512006-05-18 00:52:35 +02002966 if (buf->l == BUFSIZE)
2967 return 0;
2968 else if (buf->r >= buf->w)
willy tarreaue0331262006-05-15 03:02:46 +02002969 return buf->data + BUFSIZE - buf->r;
2970 else
2971 return buf->w - buf->r;
2972}
2973
2974
willy tarreau0f7af912005-12-17 12:21:26 +01002975/*
willy tarreaue0331262006-05-15 03:02:46 +02002976 * Tries to realign the given buffer, and returns how many bytes can be written
2977 * there at once without overwriting anything.
2978 */
2979int buffer_realign(struct buffer *buf) {
2980 if (buf->l == 0) {
2981 /* let's realign the buffer to optimize I/O */
willy tarreaucb406512006-05-18 00:52:35 +02002982 buf->r = buf->w = buf->h = buf->lr = buf->data;
willy tarreaue0331262006-05-15 03:02:46 +02002983 }
2984 return buffer_max(buf);
2985}
2986
2987
2988/* writes <len> bytes from message <msg> to buffer <buf>. Returns 0 in case of
2989 * success, or the number of bytes available otherwise.
willy tarreau1f431b52006-05-21 14:46:15 +02002990 * FIXME-20060521: handle unaligned data.
willy tarreaue0331262006-05-15 03:02:46 +02002991 */
2992int buffer_write(struct buffer *buf, const char *msg, int len) {
2993 int max;
2994
willy tarreaucb406512006-05-18 00:52:35 +02002995 max = buffer_realign(buf);
willy tarreaue0331262006-05-15 03:02:46 +02002996
2997 if (len > max)
2998 return max;
2999
3000 memcpy(buf->r, msg, len);
3001 buf->l += len;
3002 buf->r += len;
3003 if (buf->r == buf->data + BUFSIZE)
willy tarreaucb406512006-05-18 00:52:35 +02003004 buf->r = buf->data;
willy tarreaue0331262006-05-15 03:02:46 +02003005 return 0;
3006}
3007
3008
3009/*
willy tarreaue39cd132005-12-17 13:00:18 +01003010 * returns a message to the client ; the connection is shut down for read,
3011 * and the request is cleared so that no server connection can be initiated.
3012 * The client must be in a valid state for this (HEADER, DATA ...).
3013 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01003014 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01003015 */
3016void client_retnclose(struct session *s, int len, const char *msg) {
3017 FD_CLR(s->cli_fd, StaticReadEvent);
3018 FD_SET(s->cli_fd, StaticWriteEvent);
3019 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01003020 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01003021 shutdown(s->cli_fd, SHUT_RD);
3022 s->cli_state = CL_STSHUTR;
willy tarreaue0331262006-05-15 03:02:46 +02003023 buffer_flush(s->rep);
3024 buffer_write(s->rep, msg, len);
willy tarreaue39cd132005-12-17 13:00:18 +01003025 s->req->l = 0;
3026}
3027
3028
3029/*
3030 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01003031 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01003032 */
3033void client_return(struct session *s, int len, const char *msg) {
willy tarreaue0331262006-05-15 03:02:46 +02003034 buffer_flush(s->rep);
3035 buffer_write(s->rep, msg, len);
willy tarreaue39cd132005-12-17 13:00:18 +01003036 s->req->l = 0;
3037}
3038
willy tarreaue0331262006-05-15 03:02:46 +02003039/*
3040 * Produces data for the session <s> depending on its source. Expects to be
3041 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3042 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3043 * session, which it uses to keep on being called when there is free space in
3044 * the buffer, of simply by letting an empty buffer upon return. It returns 1
3045 * if it changes the session state from CL_STSHUTR, otherwise 0.
3046 */
3047int produce_content(struct session *s) {
3048 struct buffer *rep = s->rep;
3049 struct proxy *px;
3050 struct server *sv;
willy tarreaucb406512006-05-18 00:52:35 +02003051 int msglen;
willy tarreaue0331262006-05-15 03:02:46 +02003052
3053 if (s->data_source == DATA_SRC_NONE) {
3054 s->flags &= ~SN_SELF_GEN;
3055 return 1;
3056 }
3057 else if (s->data_source == DATA_SRC_STATS) {
willy tarreau1f431b52006-05-21 14:46:15 +02003058 msglen = 0;
3059
3060 if (s->data_state == DATA_ST_INIT) { /* the function had not been called yet */
3061 unsigned int up;
3062
willy tarreaue0331262006-05-15 03:02:46 +02003063 s->flags |= SN_SELF_GEN; // more data will follow
willy tarreau1f431b52006-05-21 14:46:15 +02003064
3065 /* send the start of the HTTP response */
3066 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003067 "HTTP/1.0 200 OK\r\n"
3068 "Cache-Control: no-cache\r\n"
3069 "Connection: close\r\n"
3070 "\r\n\r\n");
3071
3072 s->logs.status = 200;
3073 client_retnclose(s, msglen, trash); // send the start of the response.
willy tarreau1f431b52006-05-21 14:46:15 +02003074 msglen = 0;
3075
willy tarreaue0331262006-05-15 03:02:46 +02003076 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
3077 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
3078 if (!(s->flags & SN_FINST_MASK))
3079 s->flags |= SN_FINST_R;
3080
3081 /* WARNING! This must fit in the first buffer !!! */
willy tarreau1f431b52006-05-21 14:46:15 +02003082 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003083 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
3084 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
3085 "<style type=\"text/css\"><!--\n"
3086 "body {"
3087 " font-family: helvetica, arial;"
3088 " font-size: 12px;"
3089 " font-weight: normal;"
3090 " color: black;"
3091 " background: white;"
3092 "}\n"
3093 "td {"
3094 " font-size: 12px;"
willy tarreaucb406512006-05-18 00:52:35 +02003095 " align: center;"
willy tarreaue0331262006-05-15 03:02:46 +02003096 "}\n"
3097 "h1 {"
3098 " font-size: xx-large;"
3099 " margin-bottom: 0.5em;"
3100 "}\n"
3101 "h2 {"
3102 " font-family: helvetica, arial;"
3103 " font-size: x-large;"
3104 " font-weight: bold;"
3105 " font-style: italic;"
3106 " color: #6020a0;"
3107 " margin-top: 0em;"
3108 " margin-bottom: 0em;"
3109 "}\n"
3110 "h3 {"
3111 " font-family: helvetica, arial;"
3112 " font-size: 16px;"
3113 " font-weight: bold;"
3114 " color: #b00040;"
3115 " background: #e8e8d0;"
3116 " margin-top: 0em;"
3117 " margin-bottom: 0em;"
3118 "}\n"
3119 "li {"
3120 " margin-top: 0.25em;"
3121 " margin-right: 2em;"
3122 "}\n"
3123 ".hr {"
3124 " margin-top: 0.25em;"
3125 " border-color: black;"
3126 " border-bottom-style: solid;"
willy tarreaucb406512006-05-18 00:52:35 +02003127 "}\n"
3128 "table.tbl { border-collapse: collapse; border-width: 1px; border-style: solid; border-color: gray;}\n"
3129 "table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; border-color: gray; }\n"
3130 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray; }\n"
3131 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
3132 "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 +02003133 "-->"
3134 "</style></head>");
3135
willy tarreaucb406512006-05-18 00:52:35 +02003136 if (buffer_write(rep, trash, msglen) != 0)
3137 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003138 msglen = 0;
willy tarreaue0331262006-05-15 03:02:46 +02003139
3140 up = (now.tv_sec - start_date.tv_sec);
3141
3142 /* WARNING! this has to fit the first packet too */
willy tarreau1f431b52006-05-21 14:46:15 +02003143 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003144 "<body><h1>" PRODUCT_NAME "</h1>\n"
3145 "<h2>Statistics Report for pid %d</h2>\n"
3146 "<hr width=\"100%%\" class=\"hr\">\n"
willy tarreau338be832006-05-21 08:58:06 +02003147 "<h3>&gt; General process information</h3>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003148 "<table border=0><tr><td align=\"left\">\n"
willy tarreaue0331262006-05-15 03:02:46 +02003149 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
3150 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
willy tarreau338be832006-05-21 08:58:06 +02003151 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
willy tarreaue0331262006-05-15 03:02:46 +02003152 "<b>maxsock = </b> %d<br>\n"
3153 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003154 "</td><td width=\"10%%\">\n"
3155 "</td><td align=\"right\">\n"
3156 "<table class=\"lgd\">"
3157 "<tr><td bgcolor=\"#C0FFC0\">&nbsp;</td><td style=\"border-style: none;\">active UP </td>"
3158 "<td bgcolor=\"#B0D0FF\">&nbsp;</td><td style=\"border-style: none;\">backup UP </td></tr>"
3159 "<tr><td bgcolor=\"#FFFFA0\"></td><td style=\"border-style: none;\">active UP, going down </td>"
3160 "<td bgcolor=\"#C060FF\"></td><td style=\"border-style: none;\">backup UP, going down </td></tr>"
3161 "<tr><td bgcolor=\"#FFD020\"></td><td style=\"border-style: none;\">active DOWN, going up </td>"
3162 "<td bgcolor=\"#FF80FF\"></td><td style=\"border-style: none;\">backup DOWN, going up </td></tr>"
3163 "<tr><td bgcolor=\"#FF9090\"></td><td style=\"border-style: none;\">active or backup DOWN &nbsp;</td>"
3164 "<td bgcolor=\"#E0E0E0\"></td><td style=\"border-style: none;\">not checked </td></tr>"
3165 "</table>\n"
3166 "</tr></table>\n"
willy tarreaue0331262006-05-15 03:02:46 +02003167 "",
3168 pid, pid, global.nbproc,
3169 up / 86400, (up % 86400) / 3600,
3170 (up % 3600) / 60, (up % 60),
willy tarreau338be832006-05-21 08:58:06 +02003171 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
3172 global.rlimit_memmax ? " MB" : "",
willy tarreaue0331262006-05-15 03:02:46 +02003173 global.rlimit_nofile,
3174 global.maxsock,
3175 global.maxconn,
3176 actconn
3177 );
willy tarreaucb406512006-05-18 00:52:35 +02003178
3179 if (buffer_write(rep, trash, msglen) != 0)
3180 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003181 msglen = 0;
3182
3183 s->data_state = DATA_ST_DATA;
3184 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
3185
willy tarreaue0331262006-05-15 03:02:46 +02003186 px = s->data_ctx.stats.px = proxy;
willy tarreau1f431b52006-05-21 14:46:15 +02003187 s->data_ctx.stats.px_st = DATA_ST_INIT;
willy tarreaue0331262006-05-15 03:02:46 +02003188 }
3189
3190 while (s->data_ctx.stats.px) {
willy tarreaucb406512006-05-18 00:52:35 +02003191 int dispatch_sess, dispatch_cum;
willy tarreau1f431b52006-05-21 14:46:15 +02003192 int failed_checks, down_trans;
willy tarreaucb406512006-05-18 00:52:35 +02003193
willy tarreau1f431b52006-05-21 14:46:15 +02003194 if (s->data_ctx.stats.px_st == DATA_ST_INIT) {
3195 /* we are on a new proxy */
willy tarreaue0331262006-05-15 03:02:46 +02003196 px = s->data_ctx.stats.px;
willy tarreau1f431b52006-05-21 14:46:15 +02003197
3198 /* skip the disabled proxies */
3199 if (px->state == PR_STSTOPPED)
3200 goto next_proxy;
3201
3202 if (s->proxy->uri_auth && s->proxy->uri_auth->scope) {
3203 /* we have a limited scope, we have to check the proxy name */
3204 struct stat_scope *scope;
3205 int len;
3206
3207 len = strlen(px->id);
3208 scope = s->proxy->uri_auth->scope;
3209
3210 while (scope) {
3211 /* match exact proxy name */
3212 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
3213 break;
3214
3215 /* match '.' which means 'self' proxy */
3216 if (!strcmp(scope->px_id, ".") && px == s->proxy)
3217 break;
3218 scope = scope->next;
3219 }
3220
3221 /* proxy name not found */
3222 if (scope == NULL)
3223 goto next_proxy;
3224 }
3225
3226 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003227 "<h3>&gt; Proxy instance %s : "
3228 "%d conns (maxconn=%d), %d queued (%d unassigned), %d total conns</h3>\n"
3229 "",
3230 px->id,
3231 px->nbconn, px->maxconn, px->totpend, px->nbpend, px->cum_conn);
3232
3233 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaucb406512006-05-18 00:52:35 +02003234 "<table cols=\"13\" class=\"tbl\">\n"
3235 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
3236 "<th colspan=5>Server</th>"
3237 "<th colspan=2>Queue</th>"
3238 "<th colspan=4>Sessions</th>"
3239 "<th colspan=2>Checks</th></tr>\n"
3240 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
3241 "<th>Name</th><th>Weight</th><th>Status</th><th>Act.</th><th>Bck.</th>"
3242 "<th>Curr.</th><th>Max.</th>"
3243 "<th>Curr.</th><th>Max.</th><th>Limit</th><th>Cumul.</th>"
3244 "<th>Failed</th><th>Fatal</th></tr>\n");
willy tarreaue0331262006-05-15 03:02:46 +02003245
3246 if (buffer_write(rep, trash, msglen) != 0)
3247 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003248 msglen = 0;
3249
willy tarreaue0331262006-05-15 03:02:46 +02003250 s->data_ctx.stats.sv = px->srv;
willy tarreau1f431b52006-05-21 14:46:15 +02003251 s->data_ctx.stats.px_st = DATA_ST_DATA;
willy tarreaue0331262006-05-15 03:02:46 +02003252 }
3253
willy tarreaucb406512006-05-18 00:52:35 +02003254 px = s->data_ctx.stats.px;
3255
willy tarreau1f431b52006-05-21 14:46:15 +02003256 /* stats.sv has been initialized above */
willy tarreaue0331262006-05-15 03:02:46 +02003257 while (s->data_ctx.stats.sv != NULL) {
willy tarreaucb406512006-05-18 00:52:35 +02003258 static char *act_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FFD020", /*failing*/"#FFFFA0", /*up*/"#C0FFC0", /*unchecked*/"#E0E0E0" };
3259 static char *bck_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FF80ff", /*failing*/"#C060FF", /*up*/"#B0D0FF", /*unchecked*/"#E0E0E0" };
3260 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
3261 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP */
3262
willy tarreaue0331262006-05-15 03:02:46 +02003263 sv = s->data_ctx.stats.sv;
willy tarreaucb406512006-05-18 00:52:35 +02003264
willy tarreaucb406512006-05-18 00:52:35 +02003265 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
3266 if (!(sv->state & SRV_CHECKED))
3267 sv_state = 4;
3268 else if (sv->state & SRV_RUNNING)
3269 if (sv->health == sv->rise + sv->fall - 1)
3270 sv_state = 3; /* UP */
3271 else
3272 sv_state = 2; /* going down */
3273 else
3274 if (sv->health)
3275 sv_state = 1; /* going up */
3276 else
3277 sv_state = 0; /* DOWN */
3278
3279 /* name, weight */
willy tarreau1f431b52006-05-21 14:46:15 +02003280 msglen += snprintf(trash, sizeof(trash),
willy tarreaucb406512006-05-18 00:52:35 +02003281 "<tr align=center bgcolor=\"%s\"><td>%s</td><td>%d</td><td>",
3282 (sv->state & SRV_BACKUP) ? bck_tab_bg[sv_state] : act_tab_bg[sv_state],
3283 sv->id, sv->uweight+1);
3284 /* status */
3285 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, srv_hlt_st[sv_state],
3286 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
3287 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
3288
3289 /* act, bck */
3290 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3291 "</td><td>%s</td><td>%s</td>",
willy tarreaue0331262006-05-15 03:02:46 +02003292 (sv->state & SRV_BACKUP) ? "-" : "Y",
3293 (sv->state & SRV_BACKUP) ? "Y" : "-");
willy tarreaucb406512006-05-18 00:52:35 +02003294
3295 /* queue : current, max */
3296 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3297 "<td align=right>%d</td><td align=right>%d</td>",
3298 sv->nbpend, sv->nbpend_max);
3299
3300 /* sessions : current, max, limit, cumul */
3301 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3302 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>",
3303 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess);
3304
3305 /* failures : unique, fatal */
willy tarreau338be832006-05-21 08:58:06 +02003306 if (sv->state & SRV_CHECKED)
3307 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3308 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3309 sv->failed_checks, sv->down_trans);
3310 else
3311 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3312 "<td align=right>-</td><td align=right>-</td></tr>\n");
willy tarreaucb406512006-05-18 00:52:35 +02003313
willy tarreau1f431b52006-05-21 14:46:15 +02003314 if (buffer_write(rep, trash, msglen) != 0)
3315 return 0;
3316 msglen = 0;
3317
3318 s->data_ctx.stats.sv = sv->next;
3319 } /* while sv */
3320
3321 /* now we are past the last server, we'll dump information about the dispatcher */
3322
3323 /* We have to count down from the proxy to the servers to tell how
3324 * many sessions are on the dispatcher, and how many checks have
3325 * failed. We cannot count this during the servers dump because it
3326 * might be interrupted multiple times.
3327 */
3328 dispatch_sess = px->nbconn;
3329 dispatch_cum = px->cum_conn;
3330 failed_checks = down_trans = 0;
3331
3332 sv = px->srv;
3333 while (sv) {
3334 dispatch_sess -= sv->cur_sess;
3335 dispatch_cum -= sv->cum_sess;
3336 failed_checks += sv->failed_checks;
3337 down_trans += sv->down_trans;
willy tarreaue0331262006-05-15 03:02:46 +02003338 sv = sv->next;
willy tarreau1f431b52006-05-21 14:46:15 +02003339 }
willy tarreaucb406512006-05-18 00:52:35 +02003340
willy tarreau1f431b52006-05-21 14:46:15 +02003341 /* name, weight, status, act, bck */
3342 msglen += snprintf(trash + msglen, sizeof(trash),
3343 "<tr align=center bgcolor=\"#e8e8d0\">"
3344 "<td>Dispatcher</td><td>-</td>"
3345 "<td>%s</td><td>-</td><td>-</td>",
3346 px->state == PR_STRUN ? "UP" : "DOWN");
willy tarreaucb406512006-05-18 00:52:35 +02003347
willy tarreau1f431b52006-05-21 14:46:15 +02003348 /* queue : current, max */
3349 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3350 "<td align=right>%d</td><td align=right>%d</td>",
3351 px->nbpend, px->nbpend_max);
willy tarreaucb406512006-05-18 00:52:35 +02003352
willy tarreau1f431b52006-05-21 14:46:15 +02003353 /* sessions : current, max, limit, cumul. */
3354 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3355 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>",
3356 dispatch_sess, px->nbconn_max, px->maxconn, dispatch_cum);
willy tarreaucb406512006-05-18 00:52:35 +02003357
willy tarreau1f431b52006-05-21 14:46:15 +02003358 /* failures : unique, fatal */
3359 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3360 "<td align=right>-</td><td align=right>-</td></tr>\n");
willy tarreaucb406512006-05-18 00:52:35 +02003361
willy tarreaucb406512006-05-18 00:52:35 +02003362
willy tarreau1f431b52006-05-21 14:46:15 +02003363 /* now the summary for the whole proxy */
3364 /* name, weight, status, act, bck */
3365 msglen += snprintf(trash + msglen, sizeof(trash),
3366 "<tr align=center style=\"color: #ffff80; background: #20C0C0;\">"
3367 "<td><b>Total</b></td><td>-</td>"
3368 "<td><b>%s</b></td><td><b>%d</b></td><td><b>%d</b></td>",
3369 (px->state == PR_STRUN && ((px->srv == NULL) || px->srv_act || px->srv_bck)) ? "UP" : "DOWN",
3370 px->srv_act, px->srv_bck);
willy tarreaucb406512006-05-18 00:52:35 +02003371
willy tarreau1f431b52006-05-21 14:46:15 +02003372 /* queue : current, max */
3373 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3374 "<td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
3375 px->totpend, px->nbpend_max);
willy tarreaucb406512006-05-18 00:52:35 +02003376
willy tarreau1f431b52006-05-21 14:46:15 +02003377 /* sessions : current, max, limit, cumul */
3378 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3379 "<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>",
3380 px->nbconn, px->nbconn_max, px->maxconn, px->cum_conn);
willy tarreaucb406512006-05-18 00:52:35 +02003381
willy tarreau1f431b52006-05-21 14:46:15 +02003382 /* failures : unique, fatal */
3383 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3384 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3385 failed_checks, down_trans);
willy tarreaucb406512006-05-18 00:52:35 +02003386
willy tarreau1f431b52006-05-21 14:46:15 +02003387 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, "</table><p>\n");
3388
3389 if (buffer_write(rep, trash, msglen) != 0)
3390 return 0;
3391 msglen = 0;
3392
3393 s->data_ctx.stats.px_st = DATA_ST_INIT;
3394 next_proxy:
3395 s->data_ctx.stats.px = px->next;
willy tarreaucb406512006-05-18 00:52:35 +02003396 } /* proxy loop */
willy tarreaue0331262006-05-15 03:02:46 +02003397 /* here, we just have reached the sv == NULL and px == NULL */
3398 s->flags &= ~SN_SELF_GEN;
3399 return 1;
3400 }
3401 else {
3402 /* unknown data source */
3403 s->logs.status = 500;
3404 client_retnclose(s, s->proxy->errmsg.len500, s->proxy->errmsg.msg500);
3405 if (!(s->flags & SN_ERR_MASK))
3406 s->flags |= SN_ERR_PRXCOND;
3407 if (!(s->flags & SN_FINST_MASK))
3408 s->flags |= SN_FINST_R;
3409 s->flags &= SN_SELF_GEN;
3410 return 1;
3411 }
3412}
3413
3414
willy tarreau9fe663a2005-12-17 13:02:59 +01003415/*
3416 * send a log for the session when we have enough info about it
3417 */
3418void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003419 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01003420 struct proxy *p = s->proxy;
3421 int log;
3422 char *uri;
3423 char *pxid;
3424 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01003425 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01003426
3427 /* This is a first attempt at a better logging system.
3428 * For now, we rely on send_log() to provide the date, although it obviously
3429 * is the date of the log and not of the request, and most fields are not
3430 * computed.
3431 */
3432
willy tarreaua1598082005-12-17 13:08:06 +01003433 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01003434
willy tarreau8a86dbf2005-12-18 00:45:59 +01003435 if (s->cli_addr.ss_family == AF_INET)
3436 inet_ntop(AF_INET,
3437 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3438 pn, sizeof(pn));
3439 else
3440 inet_ntop(AF_INET6,
3441 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3442 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01003443
willy tarreauc1cae632005-12-17 14:12:23 +01003444 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01003445 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01003446 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01003447
willy tarreauc1cae632005-12-17 14:12:23 +01003448 tm = localtime(&s->logs.tv_accept.tv_sec);
3449 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01003450 char tmpline[MAX_SYSLOG_LEN], *h;
3451 int hdr;
3452
3453 h = tmpline;
3454 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
3455 *(h++) = ' ';
3456 *(h++) = '{';
3457 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
3458 if (hdr)
3459 *(h++) = '|';
3460 if (s->req_cap[hdr] != NULL)
3461 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
3462 }
3463 *(h++) = '}';
3464 }
3465
3466 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
3467 *(h++) = ' ';
3468 *(h++) = '{';
3469 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
3470 if (hdr)
3471 *(h++) = '|';
3472 if (s->rsp_cap[hdr] != NULL)
3473 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
3474 }
3475 *(h++) = '}';
3476 }
3477
3478 if (h < tmpline + sizeof(tmpline) - 4) {
3479 *(h++) = ' ';
3480 *(h++) = '"';
3481 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
3482 *(h++) = '"';
3483 }
3484 *h = '\0';
3485
willy tarreau5e69b162006-05-12 19:49:37 +02003486 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 +01003487 pn,
3488 (s->cli_addr.ss_family == AF_INET) ?
3489 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3490 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01003491 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3492 tm->tm_hour, tm->tm_min, tm->tm_sec,
3493 pxid, srv,
3494 s->logs.t_request,
willy tarreauf32f5242006-05-02 22:54:52 +02003495 (s->logs.t_queue >= 0) ? s->logs.t_queue - s->logs.t_request : -1,
3496 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreaua1598082005-12-17 13:08:06 +01003497 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003498 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3499 s->logs.status,
3500 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01003501 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
3502 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01003503 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
3504 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
3505 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
3506 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau5e69b162006-05-12 19:49:37 +02003507 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3508 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01003509 }
3510 else {
willy tarreau5f15c552006-05-13 18:37:04 +02003511 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 +01003512 pn,
3513 (s->cli_addr.ss_family == AF_INET) ?
3514 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3515 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01003516 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3517 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01003518 pxid, srv,
willy tarreau5f15c552006-05-13 18:37:04 +02003519 (s->logs.t_queue >= 0) ? s->logs.t_queue : -1,
3520 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003521 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3522 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01003523 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01003524 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreau5e69b162006-05-12 19:49:37 +02003525 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3526 s->logs.srv_queue_size, s->logs.prx_queue_size);
willy tarreaua1598082005-12-17 13:08:06 +01003527 }
3528
3529 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003530}
3531
willy tarreaue39cd132005-12-17 13:00:18 +01003532
3533/*
willy tarreau0f7af912005-12-17 12:21:26 +01003534 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01003535 * to an accept. It tries to accept as many connections as possible.
3536 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01003537 */
3538int event_accept(int fd) {
3539 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003540 struct session *s;
3541 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01003542 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01003543 int max_accept;
3544
3545 if (global.nbproc > 1)
3546 max_accept = 8; /* let other processes catch some connections too */
3547 else
3548 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003549
willy tarreauc2becdc2006-03-19 19:36:48 +01003550 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003551 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003552 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01003553
willy tarreaub1285d52005-12-18 01:20:14 +01003554 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
3555 switch (errno) {
3556 case EAGAIN:
3557 case EINTR:
3558 case ECONNABORTED:
3559 return 0; /* nothing more to accept */
3560 case ENFILE:
3561 send_log(p, LOG_EMERG,
3562 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
3563 p->id, maxfd);
3564 return 0;
3565 case EMFILE:
3566 send_log(p, LOG_EMERG,
3567 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
3568 p->id, maxfd);
3569 return 0;
3570 case ENOBUFS:
3571 case ENOMEM:
3572 send_log(p, LOG_EMERG,
3573 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
3574 p->id, maxfd);
3575 return 0;
3576 default:
3577 return 0;
3578 }
3579 }
willy tarreau0f7af912005-12-17 12:21:26 +01003580
willy tarreau5cbea6f2005-12-17 12:48:26 +01003581 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
3582 Alert("out of memory in event_accept().\n");
3583 FD_CLR(fd, StaticReadEvent);
3584 p->state = PR_STIDLE;
3585 close(cfd);
3586 return 0;
3587 }
willy tarreau0f7af912005-12-17 12:21:26 +01003588
willy tarreaub1285d52005-12-18 01:20:14 +01003589 /* if this session comes from a known monitoring system, we want to ignore
3590 * it as soon as possible, which means closing it immediately for TCP.
3591 */
3592 s->flags = 0;
3593 if (addr.ss_family == AF_INET &&
3594 p->mon_mask.s_addr &&
3595 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
3596 if (p->mode == PR_MODE_TCP) {
3597 close(cfd);
3598 pool_free(session, s);
3599 continue;
3600 }
3601 s->flags |= SN_MONITOR;
3602 }
3603
willy tarreau5cbea6f2005-12-17 12:48:26 +01003604 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3605 Alert("out of memory in event_accept().\n");
3606 FD_CLR(fd, StaticReadEvent);
3607 p->state = PR_STIDLE;
3608 close(cfd);
3609 pool_free(session, s);
3610 return 0;
3611 }
willy tarreau0f7af912005-12-17 12:21:26 +01003612
willy tarreau5cbea6f2005-12-17 12:48:26 +01003613 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01003614 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003615 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
3616 close(cfd);
3617 pool_free(task, t);
3618 pool_free(session, s);
3619 return 0;
3620 }
willy tarreau0f7af912005-12-17 12:21:26 +01003621
willy tarreau5cbea6f2005-12-17 12:48:26 +01003622 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
3623 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
3624 (char *) &one, sizeof(one)) == -1)) {
3625 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
3626 close(cfd);
3627 pool_free(task, t);
3628 pool_free(session, s);
3629 return 0;
3630 }
willy tarreau0f7af912005-12-17 12:21:26 +01003631
willy tarreaub952e1d2005-12-18 01:31:20 +01003632 if (p->options & PR_O_TCP_CLI_KA)
3633 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
3634
willy tarreau9fe663a2005-12-17 13:02:59 +01003635 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02003636 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
willy tarreau9fe663a2005-12-17 13:02:59 +01003637 t->state = TASK_IDLE;
3638 t->process = process_session;
3639 t->context = s;
3640
3641 s->task = t;
3642 s->proxy = p;
3643 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
3644 s->srv_state = SV_STIDLE;
3645 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01003646
willy tarreau9fe663a2005-12-17 13:02:59 +01003647 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
3648 s->cli_fd = cfd;
3649 s->srv_fd = -1;
willy tarreau9e138862006-05-14 23:06:28 +02003650 s->req_line.len = -1;
3651 s->auth_hdr.len = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003652 s->srv = NULL;
Willy TARREAU1a71cc12006-05-14 09:10:03 +02003653 s->pend_pos = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01003654 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01003655
willy tarreaub1285d52005-12-18 01:20:14 +01003656 if (s->flags & SN_MONITOR)
3657 s->logs.logwait = 0;
3658 else
3659 s->logs.logwait = p->to_log;
3660
willy tarreaua1598082005-12-17 13:08:06 +01003661 s->logs.tv_accept = now;
3662 s->logs.t_request = -1;
willy tarreauf32f5242006-05-02 22:54:52 +02003663 s->logs.t_queue = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003664 s->logs.t_connect = -1;
3665 s->logs.t_data = -1;
3666 s->logs.t_close = 0;
3667 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01003668 s->logs.cli_cookie = NULL;
3669 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01003670 s->logs.status = -1;
3671 s->logs.bytes = 0;
willy tarreau5e69b162006-05-12 19:49:37 +02003672 s->logs.prx_queue_size = 0; /* we get the number of pending conns before us */
3673 s->logs.srv_queue_size = 0; /* we will get this number soon */
willy tarreau9fe663a2005-12-17 13:02:59 +01003674
willy tarreaue0331262006-05-15 03:02:46 +02003675 s->data_source = DATA_SRC_NONE;
willy tarreaue0331262006-05-15 03:02:46 +02003676
willy tarreau2f6ba652005-12-17 13:57:42 +01003677 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02003678 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01003679
willy tarreau4302f492005-12-18 01:00:37 +01003680 if (p->nb_req_cap > 0) {
3681 if ((s->req_cap =
3682 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
3683 == NULL) { /* no memory */
3684 close(cfd); /* nothing can be done for this fd without memory */
3685 pool_free(task, t);
3686 pool_free(session, s);
3687 return 0;
3688 }
3689 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
3690 }
3691 else
3692 s->req_cap = NULL;
3693
3694 if (p->nb_rsp_cap > 0) {
3695 if ((s->rsp_cap =
3696 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
3697 == NULL) { /* no memory */
3698 if (s->req_cap != NULL)
3699 pool_free_to(p->req_cap_pool, s->req_cap);
3700 close(cfd); /* nothing can be done for this fd without memory */
3701 pool_free(task, t);
3702 pool_free(session, s);
3703 return 0;
3704 }
3705 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
3706 }
3707 else
3708 s->rsp_cap = NULL;
3709
willy tarreau5cbea6f2005-12-17 12:48:26 +01003710 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
3711 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003712 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003713 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01003714
willy tarreau8a86dbf2005-12-18 00:45:59 +01003715 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003716 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003717 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003718 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01003719
willy tarreau9fe663a2005-12-17 13:02:59 +01003720 if (p->to_log) {
3721 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01003722 if (s->logs.logwait & LW_CLIP)
3723 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01003724 sess_log(s);
3725 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01003726 else if (s->cli_addr.ss_family == AF_INET) {
3727 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
3728 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
3729 sn, sizeof(sn)) &&
3730 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3731 pn, sizeof(pn))) {
3732 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3733 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
3734 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
3735 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3736 }
3737 }
3738 else {
3739 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
3740 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
3741 sn, sizeof(sn)) &&
3742 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
3743 pn, sizeof(pn))) {
3744 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3745 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
3746 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
3747 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3748 }
3749 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003750 }
willy tarreau0f7af912005-12-17 12:21:26 +01003751
willy tarreau982249e2005-12-18 00:57:06 +01003752 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01003753 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003754 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01003755 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01003756 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003757 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003758 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01003759 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01003760
willy tarreau8a86dbf2005-12-18 00:45:59 +01003761 if (s->cli_addr.ss_family == AF_INET) {
3762 char pn[INET_ADDRSTRLEN];
3763 inet_ntop(AF_INET,
3764 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3765 pn, sizeof(pn));
3766
3767 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3768 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3769 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
3770 }
3771 else {
3772 char pn[INET6_ADDRSTRLEN];
3773 inet_ntop(AF_INET6,
3774 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3775 pn, sizeof(pn));
3776
3777 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3778 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3779 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3780 }
3781
willy tarreauef900ab2005-12-17 12:52:52 +01003782 write(1, trash, len);
3783 }
willy tarreau0f7af912005-12-17 12:21:26 +01003784
willy tarreau5cbea6f2005-12-17 12:48:26 +01003785 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003786 if (s->rsp_cap != NULL)
3787 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3788 if (s->req_cap != NULL)
3789 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003790 close(cfd); /* nothing can be done for this fd without memory */
3791 pool_free(task, t);
3792 pool_free(session, s);
3793 return 0;
3794 }
willy tarreau4302f492005-12-18 01:00:37 +01003795
willy tarreau5cbea6f2005-12-17 12:48:26 +01003796 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003797 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003798 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3799 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003800 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003801 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003802
willy tarreau5cbea6f2005-12-17 12:48:26 +01003803 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3804 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003805 if (s->rsp_cap != NULL)
3806 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3807 if (s->req_cap != NULL)
3808 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003809 close(cfd); /* nothing can be done for this fd without memory */
3810 pool_free(task, t);
3811 pool_free(session, s);
3812 return 0;
3813 }
3814 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003815 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003816 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 +01003817
willy tarreau5cbea6f2005-12-17 12:48:26 +01003818 fdtab[cfd].read = &event_cli_read;
3819 fdtab[cfd].write = &event_cli_write;
3820 fdtab[cfd].owner = t;
3821 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003822
willy tarreaub1285d52005-12-18 01:20:14 +01003823 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3824 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3825 /* Either we got a request from a monitoring system on an HTTP instance,
3826 * or we're in health check mode with the 'httpchk' option enabled. In
3827 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3828 */
3829 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3830 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3831 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003832 }
3833 else {
3834 FD_SET(cfd, StaticReadEvent);
3835 }
3836
willy tarreaub952e1d2005-12-18 01:31:20 +01003837#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3838 if (PrevReadEvent) {
3839 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3840 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3841 }
3842#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003843 fd_insert(cfd);
3844
3845 tv_eternity(&s->cnexpire);
3846 tv_eternity(&s->srexpire);
3847 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003848 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003849 tv_eternity(&s->cwexpire);
3850
willy tarreaub1285d52005-12-18 01:20:14 +01003851 if (s->proxy->clitimeout) {
3852 if (FD_ISSET(cfd, StaticReadEvent))
3853 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3854 if (FD_ISSET(cfd, StaticWriteEvent))
3855 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3856 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003857
willy tarreaub1285d52005-12-18 01:20:14 +01003858 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003859
3860 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003861
3862 if (p->mode != PR_MODE_HEALTH)
3863 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003864
3865 p->nbconn++;
willy tarreaucb406512006-05-18 00:52:35 +02003866 if (p->nbconn > p->nbconn_max)
3867 p->nbconn_max = p->nbconn;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003868 actconn++;
3869 totalconn++;
3870
willy tarreaub952e1d2005-12-18 01:31:20 +01003871 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003872 } /* end of while (p->nbconn < p->maxconn) */
3873 return 0;
3874}
willy tarreau0f7af912005-12-17 12:21:26 +01003875
willy tarreau0f7af912005-12-17 12:21:26 +01003876
willy tarreau5cbea6f2005-12-17 12:48:26 +01003877/*
3878 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003879 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3880 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003881 * or -1 if an error occured.
3882 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003883int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003884 struct task *t = fdtab[fd].owner;
3885 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003886 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003887 socklen_t lskerr = sizeof(skerr);
3888
willy tarreau05be12b2006-03-19 19:35:00 +01003889 skerr = 1;
3890 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3891 || (skerr != 0)) {
3892 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003893 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003894 fdtab[fd].state = FD_STERROR;
3895 FD_CLR(fd, StaticWriteEvent);
3896 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003897 else if (s->result != -1) {
3898 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003899 if (s->proxy->options & PR_O_HTTP_CHK) {
3900 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003901 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003902 * so we'll send the request, and won't wake the checker up now.
3903 */
3904#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003905 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003906#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003907 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003908#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003909 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003910 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3911 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3912 return 0;
3913 }
willy tarreau05be12b2006-03-19 19:35:00 +01003914 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003915 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003916 FD_CLR(fd, StaticWriteEvent);
3917 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003918 }
3919 else {
3920 /* good TCP connection is enough */
3921 s->result = 1;
3922 }
3923 }
3924
3925 task_wakeup(&rq, t);
3926 return 0;
3927}
3928
willy tarreau0f7af912005-12-17 12:21:26 +01003929
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003930/*
3931 * This function is used only for server health-checks. It handles
3932 * the server's reply to an HTTP request. It returns 1 if the server replies
3933 * 2xx or 3xx (valid responses), or -1 in other cases.
3934 */
3935int event_srv_chk_r(int fd) {
3936 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003937 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003938 struct task *t = fdtab[fd].owner;
3939 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003940 int skerr;
3941 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003942
willy tarreaua4a583a2005-12-18 01:39:19 +01003943 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003944
willy tarreau05be12b2006-03-19 19:35:00 +01003945 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3946 if (!skerr) {
3947#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003948 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003949#else
willy tarreau05be12b2006-03-19 19:35:00 +01003950 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3951 * but the connection was closed on the remote end. Fortunately, recv still
3952 * works correctly and we don't need to do the getsockopt() on linux.
3953 */
3954 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003955#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003956
3957 if ((len >= sizeof("HTTP/1.0 000")) &&
3958 !memcmp(reply, "HTTP/1.", 7) &&
3959 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3960 result = 1;
3961 }
3962
3963 if (result == -1)
3964 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003965
3966 if (s->result != -1)
3967 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003968
3969 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003970 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003971 return 0;
3972}
3973
3974
3975/*
3976 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3977 * and moves <end> just after the end of <str>.
3978 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3979 * the shift value (positive or negative) is returned.
3980 * If there's no space left, the move is not done.
3981 *
3982 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003983int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003984 int delta;
3985 int len;
3986
3987 len = strlen(str);
3988 delta = len - (end - pos);
3989
3990 if (delta + b->r >= b->data + BUFSIZE)
3991 return 0; /* no space left */
3992
3993 /* first, protect the end of the buffer */
3994 memmove(end + delta, end, b->data + b->l - end);
3995
3996 /* now, copy str over pos */
3997 memcpy(pos, str,len);
3998
willy tarreau5cbea6f2005-12-17 12:48:26 +01003999 /* we only move data after the displaced zone */
4000 if (b->r > pos) b->r += delta;
4001 if (b->w > pos) b->w += delta;
4002 if (b->h > pos) b->h += delta;
4003 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01004004 b->l += delta;
4005
4006 return delta;
4007}
4008
willy tarreau8337c6b2005-12-17 13:41:01 +01004009/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01004010 * len is 0.
4011 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004012int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01004013 int delta;
4014
4015 delta = len - (end - pos);
4016
4017 if (delta + b->r >= b->data + BUFSIZE)
4018 return 0; /* no space left */
4019
Willy TARREAUe78ae262006-01-08 01:24:12 +01004020 if (b->data + b->l < end)
4021 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
4022 return 0;
4023
willy tarreau0f7af912005-12-17 12:21:26 +01004024 /* first, protect the end of the buffer */
4025 memmove(end + delta, end, b->data + b->l - end);
4026
4027 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01004028 if (len)
4029 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01004030
willy tarreau5cbea6f2005-12-17 12:48:26 +01004031 /* we only move data after the displaced zone */
4032 if (b->r > pos) b->r += delta;
4033 if (b->w > pos) b->w += delta;
4034 if (b->h > pos) b->h += delta;
4035 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01004036 b->l += delta;
4037
4038 return delta;
4039}
4040
4041
4042int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
4043 char *old_dst = dst;
4044
4045 while (*str) {
4046 if (*str == '\\') {
4047 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01004048 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004049 int len, num;
4050
4051 num = *str - '0';
4052 str++;
4053
willy tarreau8a86dbf2005-12-18 00:45:59 +01004054 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01004055 len = matches[num].rm_eo - matches[num].rm_so;
4056 memcpy(dst, src + matches[num].rm_so, len);
4057 dst += len;
4058 }
4059
4060 }
4061 else if (*str == 'x') {
4062 unsigned char hex1, hex2;
4063 str++;
4064
willy tarreauc1f47532005-12-18 01:08:26 +01004065 hex1 = toupper(*str++) - '0';
4066 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01004067
4068 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
4069 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
4070 *dst++ = (hex1<<4) + hex2;
4071 }
4072 else
4073 *dst++ = *str++;
4074 }
4075 else
4076 *dst++ = *str++;
4077 }
4078 *dst = 0;
4079 return dst - old_dst;
4080}
4081
willy tarreauc1f47532005-12-18 01:08:26 +01004082static int ishex(char s)
4083{
4084 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
4085}
4086
4087/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
4088char *check_replace_string(char *str)
4089{
4090 char *err = NULL;
4091 while (*str) {
4092 if (*str == '\\') {
4093 err = str; /* in case of a backslash, we return the pointer to it */
4094 str++;
4095 if (!*str)
4096 return err;
4097 else if (isdigit((int)*str))
4098 err = NULL;
4099 else if (*str == 'x') {
4100 str++;
4101 if (!ishex(*str))
4102 return err;
4103 str++;
4104 if (!ishex(*str))
4105 return err;
4106 err = NULL;
4107 }
4108 else {
4109 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
4110 err = NULL;
4111 }
4112 }
4113 str++;
4114 }
4115 return err;
4116}
4117
willy tarreau0f7af912005-12-17 12:21:26 +01004118/*
4119 * manages the client FSM and its socket. BTW, it also tries to handle the
4120 * cookie. It returns 1 if a state has changed (and a resync may be needed),
4121 * 0 else.
4122 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004123int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004124 int s = t->srv_state;
4125 int c = t->cli_state;
4126 struct buffer *req = t->req;
4127 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004128 int method_checked = 0;
4129 appsess *asession_temp = NULL;
4130 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01004131
willy tarreau750a4722005-12-17 13:21:24 +01004132#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01004133 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
4134 cli_stnames[c], srv_stnames[s],
4135 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4136 t->crexpire.tv_sec, t->crexpire.tv_usec,
4137 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01004138#endif
willy tarreau0f7af912005-12-17 12:21:26 +01004139 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4140 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4141 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4142 //);
4143 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004144 /* now parse the partial (or complete) headers */
4145 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
4146 char *ptr;
4147 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01004148 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01004149
willy tarreau5cbea6f2005-12-17 12:48:26 +01004150 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01004151
willy tarreau0f7af912005-12-17 12:21:26 +01004152 /* look for the end of the current header */
4153 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
4154 ptr++;
4155
willy tarreau5cbea6f2005-12-17 12:48:26 +01004156 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004157 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02004158
4159 /*
4160 * first, let's check that it's not a leading empty line, in
4161 * which case we'll ignore and remove it (according to RFC2616).
4162 */
4163 if (req->h == req->data) {
4164 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4165 if (ptr > req->r - 2) {
4166 /* this is a partial header, let's wait for more to come */
4167 req->lr = ptr;
4168 break;
4169 }
4170
4171 /* now we know that *ptr is either \r or \n,
4172 * and that there are at least 1 char after it.
4173 */
4174 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4175 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4176 else
4177 req->lr = ptr + 2; /* \r\n or \n\r */
4178 /* ignore empty leading lines */
4179 buffer_replace2(req, req->h, req->lr, NULL, 0);
4180 req->h = req->lr;
4181 continue;
4182 }
4183
willy tarreau5cbea6f2005-12-17 12:48:26 +01004184 /* we can only get here after an end of headers */
4185 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01004186
willy tarreaue39cd132005-12-17 13:00:18 +01004187 if (t->flags & SN_CLDENY) {
4188 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01004189 t->logs.status = 403;
willy tarreau47ee7ad2006-05-18 01:25:36 +02004190 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now); /* let's log the request time */
willy tarreau8337c6b2005-12-17 13:41:01 +01004191 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01004192 if (!(t->flags & SN_ERR_MASK))
4193 t->flags |= SN_ERR_PRXCOND;
4194 if (!(t->flags & SN_FINST_MASK))
4195 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004196 return 1;
4197 }
4198
willy tarreau9e138862006-05-14 23:06:28 +02004199 /* Right now, we know that we have processed the entire headers
4200 * and that unwanted requests have been filtered out. We can do
4201 * whatever we want.
4202 */
4203
willy tarreau9e138862006-05-14 23:06:28 +02004204 if (t->proxy->uri_auth != NULL
4205 && t->req_line.len >= t->proxy->uri_auth->uri_len + 4) { /* +4 for "GET /" */
4206 if (!memcmp(t->req_line.str + 4,
4207 t->proxy->uri_auth->uri_prefix, t->proxy->uri_auth->uri_len)
4208 && !memcmp(t->req_line.str, "GET ", 4)) {
4209 struct user_auth *user;
4210 int authenticated;
4211
4212 /* we are in front of a interceptable URI. Let's check
4213 * if there's an authentication and if it's valid.
4214 */
4215 user = t->proxy->uri_auth->users;
4216 if (!user) {
4217 /* no user auth required, it's OK */
4218 authenticated = 1;
4219 } else {
4220 authenticated = 0;
4221
4222 /* a user list is defined, we have to check.
4223 * skip 21 chars for "Authorization: Basic ".
4224 */
4225 if (t->auth_hdr.len < 21 || memcmp(t->auth_hdr.str + 14, " Basic ", 7))
4226 user = NULL;
4227
4228 while (user) {
4229 if ((t->auth_hdr.len == user->user_len + 21)
4230 && !memcmp(t->auth_hdr.str+21, user->user_pwd, user->user_len)) {
4231 authenticated = 1;
4232 break;
4233 }
4234 user = user->next;
willy tarreau9e138862006-05-14 23:06:28 +02004235 }
4236 }
4237
4238 if (!authenticated) {
4239 int msglen;
4240
4241 /* no need to go further */
4242
4243 msglen = sprintf(trash, HTTP_401_fmt, t->proxy->uri_auth->auth_realm);
4244 t->logs.status = 401;
4245 client_retnclose(t, msglen, trash);
4246 if (!(t->flags & SN_ERR_MASK))
4247 t->flags |= SN_ERR_PRXCOND;
4248 if (!(t->flags & SN_FINST_MASK))
4249 t->flags |= SN_FINST_R;
4250 return 1;
4251 }
4252
willy tarreaue0331262006-05-15 03:02:46 +02004253 t->cli_state = CL_STSHUTR;
willy tarreau950609c2006-05-18 01:23:51 +02004254 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
4255 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreaue0331262006-05-15 03:02:46 +02004256 t->data_source = DATA_SRC_STATS;
willy tarreau1f431b52006-05-21 14:46:15 +02004257 t->data_state = DATA_ST_INIT;
willy tarreaue0331262006-05-15 03:02:46 +02004258 produce_content(t);
4259 return 1;
willy tarreau9e138862006-05-14 23:06:28 +02004260 }
4261 }
4262
4263
willy tarreau5cbea6f2005-12-17 12:48:26 +01004264 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004265 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
4266 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004267 }
willy tarreau0f7af912005-12-17 12:21:26 +01004268
willy tarreau9fe663a2005-12-17 13:02:59 +01004269 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01004270 if (t->cli_addr.ss_family == AF_INET) {
4271 unsigned char *pn;
4272 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
4273 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
4274 pn[0], pn[1], pn[2], pn[3]);
4275 buffer_replace2(req, req->h, req->h, trash, len);
4276 }
4277 else if (t->cli_addr.ss_family == AF_INET6) {
4278 char pn[INET6_ADDRSTRLEN];
4279 inet_ntop(AF_INET6,
4280 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
4281 pn, sizeof(pn));
4282 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
4283 buffer_replace2(req, req->h, req->h, trash, len);
4284 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004285 }
4286
willy tarreau25c4ea52005-12-18 00:49:49 +01004287 /* add a "connection: close" line if needed */
4288 if (t->proxy->options & PR_O_HTTP_CLOSE)
4289 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
4290
willy tarreau982249e2005-12-18 00:57:06 +01004291 if (!memcmp(req->data, "POST ", 5)) {
4292 /* this is a POST request, which is not cacheable by default */
4293 t->flags |= SN_POST;
4294 }
willy tarreaucd878942005-12-17 13:27:43 +01004295
willy tarreau5cbea6f2005-12-17 12:48:26 +01004296 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004297 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01004298
willy tarreau750a4722005-12-17 13:21:24 +01004299 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004300 /* FIXME: we'll set the client in a wait state while we try to
4301 * connect to the server. Is this really needed ? wouldn't it be
willy tarreau0889c962006-04-24 14:36:48 +02004302 * better to release the maximum of system buffers instead ?
4303 * The solution is to enable the FD but set its time-out to
4304 * eternity as long as the server-side does not enable data xfer.
4305 * CL_STDATA also has to take care of this, which is done below.
4306 */
willy tarreauef900ab2005-12-17 12:52:52 +01004307 //FD_CLR(t->cli_fd, StaticReadEvent);
4308 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01004309
4310 /* FIXME: if we break here (as up to 1.1.23), having the client
4311 * shutdown its connection can lead to an abort further.
4312 * it's better to either return 1 or even jump directly to the
4313 * data state which will save one schedule.
4314 */
4315 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01004316
4317 if (!t->proxy->clitimeout ||
4318 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4319 /* If the client has no timeout, or if the server is not ready yet,
4320 * and we know for sure that it can expire, then it's cleaner to
4321 * disable the timeout on the client side so that too low values
4322 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01004323 *
4324 * FIXME-20050705: the server needs a way to re-enable this time-out
4325 * when it switches its state, otherwise a client can stay connected
4326 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01004327 */
4328 tv_eternity(&t->crexpire);
4329
willy tarreau197e8ec2005-12-17 14:10:59 +01004330 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004331 }
willy tarreau0f7af912005-12-17 12:21:26 +01004332
Willy TARREAU13032e72006-03-12 17:31:45 +01004333 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4334 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004335 /* this is a partial header, let's wait for more to come */
4336 req->lr = ptr;
4337 break;
4338 }
willy tarreau0f7af912005-12-17 12:21:26 +01004339
willy tarreau5cbea6f2005-12-17 12:48:26 +01004340 /* now we know that *ptr is either \r or \n,
4341 * and that there are at least 1 char after it.
4342 */
4343 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4344 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4345 else
4346 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01004347
willy tarreau5cbea6f2005-12-17 12:48:26 +01004348 /*
4349 * now we know that we have a full header ; we can do whatever
4350 * we want with these pointers :
4351 * req->h = beginning of header
4352 * ptr = end of header (first \r or \n)
4353 * req->lr = beginning of next line (next rep->h)
4354 * req->r = end of data (not used at this stage)
4355 */
willy tarreau0f7af912005-12-17 12:21:26 +01004356
willy tarreau12350152005-12-18 01:03:27 +01004357 if (!method_checked && (t->proxy->appsession_name != NULL) &&
4358 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
4359 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
4360
4361 /* skip ; */
4362 request_line++;
4363
4364 /* look if we have a jsessionid */
4365
4366 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
4367
4368 /* skip jsessionid= */
4369 request_line += t->proxy->appsession_name_len + 1;
4370
4371 /* First try if we allready have an appsession */
4372 asession_temp = &local_asession;
4373
4374 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4375 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
4376 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
4377 return 0;
4378 }
4379
4380 /* Copy the sessionid */
4381 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
4382 asession_temp->sessid[t->proxy->appsession_len] = 0;
4383 asession_temp->serverid = NULL;
4384
4385 /* only do insert, if lookup fails */
4386 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
4387 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4388 Alert("Not enough memory process_cli():asession:calloc().\n");
4389 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4390 return 0;
4391 }
4392 asession_temp->sessid = local_asession.sessid;
4393 asession_temp->serverid = local_asession.serverid;
4394 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004395 } /* end if (chtbl_lookup()) */
4396 else {
willy tarreau12350152005-12-18 01:03:27 +01004397 /*free wasted memory;*/
4398 pool_free_to(apools.sessid, local_asession.sessid);
4399 }
4400
4401 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4402 asession_temp->request_count++;
4403
4404#if defined(DEBUG_HASH)
4405 print_table(&(t->proxy->htbl_proxy));
4406#endif
4407
4408 if (asession_temp->serverid == NULL) {
4409 Alert("Found Application Session without matching server.\n");
4410 } else {
4411 struct server *srv = t->proxy->srv;
4412 while (srv) {
4413 if (strcmp(srv->id, asession_temp->serverid) == 0) {
4414 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4415 /* we found the server and it's usable */
4416 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004417 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004418 t->srv = srv;
4419 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01004420 } else {
willy tarreau12350152005-12-18 01:03:27 +01004421 t->flags &= ~SN_CK_MASK;
4422 t->flags |= SN_CK_DOWN;
4423 }
willy tarreaub952e1d2005-12-18 01:31:20 +01004424 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01004425 srv = srv->next;
4426 }/* end while(srv) */
4427 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01004428 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01004429 else {
4430 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
4431 }
willy tarreau598da412005-12-18 01:07:29 +01004432 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01004433 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01004434 else{
4435 //printf("No Methode-Header with Session-String\n");
4436 }
4437
willy tarreau8337c6b2005-12-17 13:41:01 +01004438 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004439 /* we have a complete HTTP request that we must log */
4440 int urilen;
4441
willy tarreaua1598082005-12-17 13:08:06 +01004442 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004443 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01004444 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01004445 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01004446 if (!(t->flags & SN_ERR_MASK))
4447 t->flags |= SN_ERR_PRXCOND;
4448 if (!(t->flags & SN_FINST_MASK))
4449 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01004450 return 1;
4451 }
4452
4453 urilen = ptr - req->h;
4454 if (urilen >= REQURI_LEN)
4455 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01004456 memcpy(t->logs.uri, req->h, urilen);
4457 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004458
willy tarreaua1598082005-12-17 13:08:06 +01004459 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01004460 sess_log(t);
4461 }
willy tarreau4302f492005-12-18 01:00:37 +01004462 else if (t->logs.logwait & LW_REQHDR) {
4463 struct cap_hdr *h;
4464 int len;
4465 for (h = t->proxy->req_cap; h; h = h->next) {
4466 if ((h->namelen + 2 <= ptr - req->h) &&
4467 (req->h[h->namelen] == ':') &&
4468 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
4469
4470 if (t->req_cap[h->index] == NULL)
4471 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4472
4473 len = ptr - (req->h + h->namelen + 2);
4474 if (len > h->len)
4475 len = h->len;
4476
4477 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
4478 t->req_cap[h->index][len]=0;
4479 }
4480 }
4481
4482 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004483
willy tarreau5cbea6f2005-12-17 12:48:26 +01004484 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004485
willy tarreau982249e2005-12-18 00:57:06 +01004486 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004487 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004488 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 +01004489 max = ptr - req->h;
4490 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004491 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004492 trash[len++] = '\n';
4493 write(1, trash, len);
4494 }
willy tarreau0f7af912005-12-17 12:21:26 +01004495
willy tarreau25c4ea52005-12-18 00:49:49 +01004496
4497 /* remove "connection: " if needed */
4498 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4499 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
4500 delete_header = 1;
4501 }
4502
willy tarreau5cbea6f2005-12-17 12:48:26 +01004503 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004504 if (!delete_header && t->proxy->req_exp != NULL
4505 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004506 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004507 char term;
4508
4509 term = *ptr;
4510 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004511 exp = t->proxy->req_exp;
4512 do {
4513 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
4514 switch (exp->action) {
4515 case ACT_ALLOW:
4516 if (!(t->flags & SN_CLDENY))
4517 t->flags |= SN_CLALLOW;
4518 break;
4519 case ACT_REPLACE:
4520 if (!(t->flags & SN_CLDENY)) {
4521 int len = exp_replace(trash, req->h, exp->replace, pmatch);
4522 ptr += buffer_replace2(req, req->h, ptr, trash, len);
4523 }
4524 break;
4525 case ACT_REMOVE:
4526 if (!(t->flags & SN_CLDENY))
4527 delete_header = 1;
4528 break;
4529 case ACT_DENY:
4530 if (!(t->flags & SN_CLALLOW))
4531 t->flags |= SN_CLDENY;
4532 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004533 case ACT_PASS: /* we simply don't deny this one */
4534 break;
willy tarreau0f7af912005-12-17 12:21:26 +01004535 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004536 break;
willy tarreau0f7af912005-12-17 12:21:26 +01004537 }
willy tarreaue39cd132005-12-17 13:00:18 +01004538 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004539 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01004540 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004541
willy tarreau240afa62005-12-17 13:14:35 +01004542 /* Now look for cookies. Conforming to RFC2109, we have to support
4543 * attributes whose name begin with a '$', and associate them with
4544 * the right cookie, if we want to delete this cookie.
4545 * So there are 3 cases for each cookie read :
4546 * 1) it's a special attribute, beginning with a '$' : ignore it.
4547 * 2) it's a server id cookie that we *MAY* want to delete : save
4548 * some pointers on it (last semi-colon, beginning of cookie...)
4549 * 3) it's an application cookie : we *MAY* have to delete a previous
4550 * "special" cookie.
4551 * At the end of loop, if a "special" cookie remains, we may have to
4552 * remove it. If no application cookie persists in the header, we
4553 * *MUST* delete it
4554 */
willy tarreau12350152005-12-18 01:03:27 +01004555 if (!delete_header &&
4556 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01004557 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01004558 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004559 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01004560 char *del_colon, *del_cookie, *colon;
4561 int app_cookies;
4562
willy tarreau5cbea6f2005-12-17 12:48:26 +01004563 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01004564 colon = p1;
4565 /* del_cookie == NULL => nothing to be deleted */
4566 del_colon = del_cookie = NULL;
4567 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004568
4569 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01004570 /* skip spaces and colons, but keep an eye on these ones */
4571 while (p1 < ptr) {
4572 if (*p1 == ';' || *p1 == ',')
4573 colon = p1;
4574 else if (!isspace((int)*p1))
4575 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004576 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01004577 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004578
4579 if (p1 == ptr)
4580 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004581
4582 /* p1 is at the beginning of the cookie name */
4583 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01004584 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004585 p2++;
4586
4587 if (p2 == ptr)
4588 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004589
4590 p3 = p2 + 1; /* skips the '=' sign */
4591 if (p3 == ptr)
4592 break;
4593
willy tarreau240afa62005-12-17 13:14:35 +01004594 p4 = p3;
4595 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004596 p4++;
4597
4598 /* here, we have the cookie name between p1 and p2,
4599 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01004600 * we can process it :
4601 *
4602 * Cookie: NAME=VALUE;
4603 * | || || |
4604 * | || || +--> p4
4605 * | || |+-------> p3
4606 * | || +--------> p2
4607 * | |+------------> p1
4608 * | +-------------> colon
4609 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01004610 */
4611
willy tarreau240afa62005-12-17 13:14:35 +01004612 if (*p1 == '$') {
4613 /* skip this one */
4614 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004615 else {
4616 /* first, let's see if we want to capture it */
4617 if (t->proxy->capture_name != NULL &&
4618 t->logs.cli_cookie == NULL &&
4619 (p4 - p1 >= t->proxy->capture_namelen) &&
4620 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4621 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004622
willy tarreau8337c6b2005-12-17 13:41:01 +01004623 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4624 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01004625 } else {
4626 if (log_len > t->proxy->capture_len)
4627 log_len = t->proxy->capture_len;
4628 memcpy(t->logs.cli_cookie, p1, log_len);
4629 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01004630 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004631 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004632
4633 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4634 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
4635 /* Cool... it's the right one */
4636 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01004637 char *delim;
4638
4639 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4640 * have the server ID betweek p3 and delim, and the original cookie between
4641 * delim+1 and p4. Otherwise, delim==p4 :
4642 *
4643 * Cookie: NAME=SRV~VALUE;
4644 * | || || | |
4645 * | || || | +--> p4
4646 * | || || +--------> delim
4647 * | || |+-----------> p3
4648 * | || +------------> p2
4649 * | |+----------------> p1
4650 * | +-----------------> colon
4651 * +------------------------> req->h
4652 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004653
willy tarreau0174f312005-12-18 01:02:42 +01004654 if (t->proxy->options & PR_O_COOK_PFX) {
4655 for (delim = p3; delim < p4; delim++)
4656 if (*delim == COOKIE_DELIM)
4657 break;
4658 }
4659 else
4660 delim = p4;
4661
4662
4663 /* Here, we'll look for the first running server which supports the cookie.
4664 * This allows to share a same cookie between several servers, for example
4665 * to dedicate backup servers to specific servers only.
willy tarreau422bb2e2006-05-10 04:27:21 +02004666 * However, to prevent clients from sticking to cookie-less backup server
4667 * when they have incidentely learned an empty cookie, we simply ignore
4668 * empty cookies and mark them as invalid.
willy tarreau0174f312005-12-18 01:02:42 +01004669 */
willy tarreau422bb2e2006-05-10 04:27:21 +02004670 if (delim == p3)
4671 srv = NULL;
4672
willy tarreau0174f312005-12-18 01:02:42 +01004673 while (srv) {
4674 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
4675 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4676 /* we found the server and it's usable */
4677 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004678 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau0174f312005-12-18 01:02:42 +01004679 t->srv = srv;
4680 break;
willy tarreau12350152005-12-18 01:03:27 +01004681 } else {
willy tarreau0174f312005-12-18 01:02:42 +01004682 /* we found a server, but it's down */
4683 t->flags &= ~SN_CK_MASK;
4684 t->flags |= SN_CK_DOWN;
4685 }
4686 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004687 srv = srv->next;
4688 }
4689
willy tarreau0174f312005-12-18 01:02:42 +01004690 if (!srv && !(t->flags & SN_CK_DOWN)) {
4691 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01004692 t->flags &= ~SN_CK_MASK;
4693 t->flags |= SN_CK_INVALID;
4694 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004695
willy tarreau0174f312005-12-18 01:02:42 +01004696 /* depending on the cookie mode, we may have to either :
4697 * - delete the complete cookie if we're in insert+indirect mode, so that
4698 * the server never sees it ;
4699 * - remove the server id from the cookie value, and tag the cookie as an
4700 * application cookie so that it does not get accidentely removed later,
4701 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01004702 */
willy tarreau0174f312005-12-18 01:02:42 +01004703 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
4704 buffer_replace2(req, p3, delim + 1, NULL, 0);
4705 p4 -= (delim + 1 - p3);
4706 ptr -= (delim + 1 - p3);
4707 del_cookie = del_colon = NULL;
4708 app_cookies++; /* protect the header from deletion */
4709 }
4710 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01004711 (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 +01004712 del_cookie = p1;
4713 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01004714 }
willy tarreau12350152005-12-18 01:03:27 +01004715 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01004716 /* now we know that we must keep this cookie since it's
4717 * not ours. But if we wanted to delete our cookie
4718 * earlier, we cannot remove the complete header, but we
4719 * can remove the previous block itself.
4720 */
4721 app_cookies++;
4722
4723 if (del_cookie != NULL) {
4724 buffer_replace2(req, del_cookie, p1, NULL, 0);
4725 p4 -= (p1 - del_cookie);
4726 ptr -= (p1 - del_cookie);
4727 del_cookie = del_colon = NULL;
4728 }
willy tarreau240afa62005-12-17 13:14:35 +01004729 }
willy tarreau12350152005-12-18 01:03:27 +01004730
4731 if ((t->proxy->appsession_name != NULL) &&
4732 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4733 /* first, let's see if the cookie is our appcookie*/
4734
4735 /* Cool... it's the right one */
4736
4737 asession_temp = &local_asession;
4738
4739 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4740 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4741 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4742 return 0;
4743 }
4744
4745 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4746 asession_temp->sessid[t->proxy->appsession_len] = 0;
4747 asession_temp->serverid = NULL;
4748
4749 /* only do insert, if lookup fails */
4750 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4751 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4752 Alert("Not enough memory process_cli():asession:calloc().\n");
4753 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4754 return 0;
4755 }
4756
4757 asession_temp->sessid = local_asession.sessid;
4758 asession_temp->serverid = local_asession.serverid;
4759 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4760 }
4761 else{
4762 /* free wasted memory */
4763 pool_free_to(apools.sessid, local_asession.sessid);
4764 }
4765
4766 if (asession_temp->serverid == NULL) {
4767 Alert("Found Application Session without matching server.\n");
4768 } else {
4769 struct server *srv = t->proxy->srv;
4770 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01004771 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01004772 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4773 /* we found the server and it's usable */
4774 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004775 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004776 t->srv = srv;
4777 break;
4778 } else {
4779 t->flags &= ~SN_CK_MASK;
4780 t->flags |= SN_CK_DOWN;
4781 }
4782 }
4783 srv = srv->next;
4784 }/* end while(srv) */
4785 }/* end else if server == NULL */
4786
4787 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01004788 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004789 }
willy tarreau240afa62005-12-17 13:14:35 +01004790
willy tarreau5cbea6f2005-12-17 12:48:26 +01004791 /* we'll have to look for another cookie ... */
4792 p1 = p4;
4793 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01004794
4795 /* There's no more cookie on this line.
4796 * We may have marked the last one(s) for deletion.
4797 * We must do this now in two ways :
4798 * - if there is no app cookie, we simply delete the header ;
4799 * - if there are app cookies, we must delete the end of the
4800 * string properly, including the colon/semi-colon before
4801 * the cookie name.
4802 */
4803 if (del_cookie != NULL) {
4804 if (app_cookies) {
4805 buffer_replace2(req, del_colon, ptr, NULL, 0);
4806 /* WARNING! <ptr> becomes invalid for now. If some code
4807 * below needs to rely on it before the end of the global
4808 * header loop, we need to correct it with this code :
willy tarreau240afa62005-12-17 13:14:35 +01004809 */
willy tarreau9e138862006-05-14 23:06:28 +02004810 ptr = del_colon;
willy tarreau240afa62005-12-17 13:14:35 +01004811 }
4812 else
4813 delete_header = 1;
4814 }
4815 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004816
4817 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004818 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01004819 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau9e138862006-05-14 23:06:28 +02004820 /* WARNING: ptr is not valid anymore, since the header may have
4821 * been deleted or truncated ! */
4822 } else {
4823 /* try to catch the first line as the request */
4824 if (t->req_line.len < 0) {
4825 t->req_line.str = req->h;
4826 t->req_line.len = ptr - req->h;
4827 }
4828
4829 /* We might also need the 'Authorization: ' header */
4830 if (t->auth_hdr.len < 0 &&
4831 t->proxy->uri_auth != NULL &&
4832 ptr > req->h + 15 &&
4833 !strncasecmp("Authorization: ", req->h, 15)) {
4834 t->auth_hdr.str = req->h;
4835 t->auth_hdr.len = ptr - req->h;
4836 }
willy tarreau0f7af912005-12-17 12:21:26 +01004837 }
willy tarreau240afa62005-12-17 13:14:35 +01004838
willy tarreau5cbea6f2005-12-17 12:48:26 +01004839 req->h = req->lr;
4840 } /* while (req->lr < req->r) */
4841
4842 /* end of header processing (even if incomplete) */
4843
willy tarreauef900ab2005-12-17 12:52:52 +01004844 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4845 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4846 * full. We cannot loop here since event_cli_read will disable it only if
4847 * req->l == rlim-data
4848 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004849 FD_SET(t->cli_fd, StaticReadEvent);
4850 if (t->proxy->clitimeout)
4851 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4852 else
4853 tv_eternity(&t->crexpire);
4854 }
4855
willy tarreaue39cd132005-12-17 13:00:18 +01004856 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01004857 * won't be able to free more later, so the session will never terminate.
4858 */
willy tarreaue39cd132005-12-17 13:00:18 +01004859 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01004860 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01004861 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01004862 if (!(t->flags & SN_ERR_MASK))
4863 t->flags |= SN_ERR_PRXCOND;
4864 if (!(t->flags & SN_FINST_MASK))
4865 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004866 return 1;
4867 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004868 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004869 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004870 tv_eternity(&t->crexpire);
4871 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004872 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004873 if (!(t->flags & SN_ERR_MASK))
4874 t->flags |= SN_ERR_CLICL;
4875 if (!(t->flags & SN_FINST_MASK))
4876 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004877 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004878 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004879 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4880
4881 /* read timeout : give up with an error message.
4882 */
4883 t->logs.status = 408;
4884 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004885 if (!(t->flags & SN_ERR_MASK))
4886 t->flags |= SN_ERR_CLITO;
4887 if (!(t->flags & SN_FINST_MASK))
4888 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004889 return 1;
4890 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004891
4892 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004893 }
4894 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004895 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004896 /* FIXME: this error handling is partly buggy because we always report
4897 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4898 * or HEADER phase. BTW, it's not logical to expire the client while
4899 * we're waiting for the server to connect.
4900 */
willy tarreau0f7af912005-12-17 12:21:26 +01004901 /* read or write error */
4902 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004903 tv_eternity(&t->crexpire);
4904 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004905 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004906 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004907 if (!(t->flags & SN_ERR_MASK))
4908 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004909 if (!(t->flags & SN_FINST_MASK)) {
4910 if (t->pend_pos)
4911 t->flags |= SN_FINST_Q;
4912 else if (s == SV_STCONN)
4913 t->flags |= SN_FINST_C;
4914 else
4915 t->flags |= SN_FINST_D;
4916 }
willy tarreau0f7af912005-12-17 12:21:26 +01004917 return 1;
4918 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004919 /* last read, or end of server write */
4920 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004921 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004922 tv_eternity(&t->crexpire);
4923 shutdown(t->cli_fd, SHUT_RD);
4924 t->cli_state = CL_STSHUTR;
4925 return 1;
4926 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004927 /* last server read and buffer empty */
4928 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004929 FD_CLR(t->cli_fd, StaticWriteEvent);
4930 tv_eternity(&t->cwexpire);
4931 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004932 /* We must ensure that the read part is still alive when switching
4933 * to shutw */
4934 FD_SET(t->cli_fd, StaticReadEvent);
4935 if (t->proxy->clitimeout)
4936 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004937 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004938 //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 +01004939 return 1;
4940 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004941 /* read timeout */
4942 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4943 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004944 tv_eternity(&t->crexpire);
4945 shutdown(t->cli_fd, SHUT_RD);
4946 t->cli_state = CL_STSHUTR;
4947 if (!(t->flags & SN_ERR_MASK))
4948 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004949 if (!(t->flags & SN_FINST_MASK)) {
4950 if (t->pend_pos)
4951 t->flags |= SN_FINST_Q;
4952 else if (s == SV_STCONN)
4953 t->flags |= SN_FINST_C;
4954 else
4955 t->flags |= SN_FINST_D;
4956 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004957 return 1;
4958 }
4959 /* write timeout */
4960 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4961 FD_CLR(t->cli_fd, StaticWriteEvent);
4962 tv_eternity(&t->cwexpire);
4963 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004964 /* We must ensure that the read part is still alive when switching
4965 * to shutw */
4966 FD_SET(t->cli_fd, StaticReadEvent);
4967 if (t->proxy->clitimeout)
4968 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4969
willy tarreau036e1ce2005-12-17 13:46:33 +01004970 t->cli_state = CL_STSHUTW;
4971 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004972 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004973 if (!(t->flags & SN_FINST_MASK)) {
4974 if (t->pend_pos)
4975 t->flags |= SN_FINST_Q;
4976 else if (s == SV_STCONN)
4977 t->flags |= SN_FINST_C;
4978 else
4979 t->flags |= SN_FINST_D;
4980 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004981 return 1;
4982 }
willy tarreau0f7af912005-12-17 12:21:26 +01004983
willy tarreauc58fc692005-12-17 14:13:08 +01004984 if (req->l >= req->rlim - req->data) {
4985 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004986 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004987 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004988 FD_CLR(t->cli_fd, StaticReadEvent);
4989 tv_eternity(&t->crexpire);
4990 }
4991 }
4992 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004993 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004994 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4995 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004996 if (!t->proxy->clitimeout ||
4997 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4998 /* If the client has no timeout, or if the server not ready yet, and we
4999 * know for sure that it can expire, then it's cleaner to disable the
5000 * timeout on the client side so that too low values cannot make the
5001 * sessions abort too early.
5002 */
willy tarreau0f7af912005-12-17 12:21:26 +01005003 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01005004 else
5005 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005006 }
5007 }
5008
5009 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01005010 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005011 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5012 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
5013 tv_eternity(&t->cwexpire);
5014 }
5015 }
5016 else { /* buffer not empty */
5017 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5018 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005019 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005020 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005021 /* FIXME: to prevent the client from expiring read timeouts during writes,
5022 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005023 t->crexpire = t->cwexpire;
5024 }
willy tarreau0f7af912005-12-17 12:21:26 +01005025 else
5026 tv_eternity(&t->cwexpire);
5027 }
5028 }
5029 return 0; /* other cases change nothing */
5030 }
5031 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005032 if (t->res_cw == RES_ERROR) {
5033 tv_eternity(&t->cwexpire);
5034 fd_delete(t->cli_fd);
5035 t->cli_state = CL_STCLOSE;
5036 if (!(t->flags & SN_ERR_MASK))
5037 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02005038 if (!(t->flags & SN_FINST_MASK)) {
5039 if (t->pend_pos)
5040 t->flags |= SN_FINST_Q;
5041 else if (s == SV_STCONN)
5042 t->flags |= SN_FINST_C;
5043 else
5044 t->flags |= SN_FINST_D;
5045 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005046 return 1;
5047 }
willy tarreaue0331262006-05-15 03:02:46 +02005048 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
5049 && !(t->flags & SN_SELF_GEN)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005050 tv_eternity(&t->cwexpire);
5051 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005052 t->cli_state = CL_STCLOSE;
5053 return 1;
5054 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005055 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
5056 tv_eternity(&t->cwexpire);
5057 fd_delete(t->cli_fd);
5058 t->cli_state = CL_STCLOSE;
5059 if (!(t->flags & SN_ERR_MASK))
5060 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005061 if (!(t->flags & SN_FINST_MASK)) {
5062 if (t->pend_pos)
5063 t->flags |= SN_FINST_Q;
5064 else if (s == SV_STCONN)
5065 t->flags |= SN_FINST_C;
5066 else
5067 t->flags |= SN_FINST_D;
5068 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005069 return 1;
5070 }
willy tarreaue0331262006-05-15 03:02:46 +02005071
5072 if (t->flags & SN_SELF_GEN) {
5073 produce_content(t);
5074 if (rep->l == 0) {
5075 tv_eternity(&t->cwexpire);
5076 fd_delete(t->cli_fd);
5077 t->cli_state = CL_STCLOSE;
5078 return 1;
5079 }
5080 }
5081
5082 if ((rep->l == 0)
5083 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005084 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5085 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
5086 tv_eternity(&t->cwexpire);
5087 }
5088 }
5089 else { /* buffer not empty */
5090 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5091 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005092 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005093 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005094 /* FIXME: to prevent the client from expiring read timeouts during writes,
5095 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005096 t->crexpire = t->cwexpire;
5097 }
willy tarreau0f7af912005-12-17 12:21:26 +01005098 else
5099 tv_eternity(&t->cwexpire);
5100 }
5101 }
5102 return 0;
5103 }
5104 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005105 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005106 tv_eternity(&t->crexpire);
5107 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005108 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005109 if (!(t->flags & SN_ERR_MASK))
5110 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02005111 if (!(t->flags & SN_FINST_MASK)) {
5112 if (t->pend_pos)
5113 t->flags |= SN_FINST_Q;
5114 else if (s == SV_STCONN)
5115 t->flags |= SN_FINST_C;
5116 else
5117 t->flags |= SN_FINST_D;
5118 }
willy tarreau0f7af912005-12-17 12:21:26 +01005119 return 1;
5120 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005121 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
5122 tv_eternity(&t->crexpire);
5123 fd_delete(t->cli_fd);
5124 t->cli_state = CL_STCLOSE;
5125 return 1;
5126 }
5127 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
5128 tv_eternity(&t->crexpire);
5129 fd_delete(t->cli_fd);
5130 t->cli_state = CL_STCLOSE;
5131 if (!(t->flags & SN_ERR_MASK))
5132 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005133 if (!(t->flags & SN_FINST_MASK)) {
5134 if (t->pend_pos)
5135 t->flags |= SN_FINST_Q;
5136 else if (s == SV_STCONN)
5137 t->flags |= SN_FINST_C;
5138 else
5139 t->flags |= SN_FINST_D;
5140 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005141 return 1;
5142 }
willy tarreauef900ab2005-12-17 12:52:52 +01005143 else if (req->l >= req->rlim - req->data) {
5144 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01005145
5146 /* FIXME-20050705: is it possible for a client to maintain a session
5147 * after the timeout by sending more data after it receives a close ?
5148 */
5149
willy tarreau0f7af912005-12-17 12:21:26 +01005150 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01005151 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01005152 FD_CLR(t->cli_fd, StaticReadEvent);
5153 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01005154 //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 +01005155 }
5156 }
5157 else {
willy tarreauef900ab2005-12-17 12:52:52 +01005158 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01005159 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
5160 FD_SET(t->cli_fd, StaticReadEvent);
5161 if (t->proxy->clitimeout)
5162 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
5163 else
5164 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01005165 //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 +01005166 }
5167 }
5168 return 0;
5169 }
5170 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005171 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005172 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005173 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 +01005174 write(1, trash, len);
5175 }
5176 return 0;
5177 }
5178 return 0;
5179}
5180
willy tarreaudfece232006-05-02 00:19:57 +02005181/* This function turns the server state into the SV_STCLOSE, and sets
5182 * indicators accordingly. Note that if <status> is 0, no message is
5183 * returned.
5184 */
5185void srv_close_with_err(struct session *t, int err, int finst, int status, int msglen, char *msg) {
5186 t->srv_state = SV_STCLOSE;
5187 if (status > 0) {
5188 t->logs.status = status;
5189 if (t->proxy->mode == PR_MODE_HTTP)
5190 client_return(t, msglen, msg);
5191 }
5192 if (!(t->flags & SN_ERR_MASK))
5193 t->flags |= err;
5194 if (!(t->flags & SN_FINST_MASK))
5195 t->flags |= finst;
5196}
5197
5198/*
5199 * This function checks the retry count during the connect() job.
5200 * It updates the session's srv_state and retries, so that the caller knows
5201 * what it has to do. It uses the last connection error to set the log when
5202 * it expires. It returns 1 when it has expired, and 0 otherwise.
5203 */
5204int srv_count_retry_down(struct session *t, int conn_err) {
5205 /* we are in front of a retryable error */
5206 t->conn_retries--;
5207 if (t->conn_retries < 0) {
5208 /* if not retryable anymore, let's abort */
5209 tv_eternity(&t->cnexpire);
5210 srv_close_with_err(t, conn_err, SN_FINST_C,
5211 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
5212
5213 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005214 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005215 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005216 if (may_dequeue_tasks(t->srv, t->proxy))
5217 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005218 return 1;
5219 }
5220 return 0;
5221}
willy tarreau0f7af912005-12-17 12:21:26 +01005222
5223/*
willy tarreaudfece232006-05-02 00:19:57 +02005224 * This function performs the retryable part of the connect() job.
5225 * It updates the session's srv_state and retries, so that the caller knows
5226 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
5227 * it needs to redispatch.
5228 */
5229int srv_retryable_connect(struct session *t) {
5230 int conn_err;
5231
5232 /* This loop ensures that we stop before the last retry in case of a
5233 * redispatchable server.
5234 */
5235 do {
5236 /* initiate a connection to the server */
5237 conn_err = connect_server(t);
5238 switch (conn_err) {
5239
5240 case SN_ERR_NONE:
5241 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
5242 t->srv_state = SV_STCONN;
5243 return 1;
5244
5245 case SN_ERR_INTERNAL:
5246 tv_eternity(&t->cnexpire);
5247 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
5248 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
5249 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02005250 if (may_dequeue_tasks(t->srv, t->proxy))
5251 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005252 return 1;
5253 }
5254 /* ensure that we have enough retries left */
willy tarreau59a6cc22006-05-12 01:29:08 +02005255 if (srv_count_retry_down(t, conn_err)) {
5256 /* let's try to offer this slot to anybody */
5257 if (may_dequeue_tasks(t->srv, t->proxy))
5258 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005259 return 1;
willy tarreau59a6cc22006-05-12 01:29:08 +02005260 }
willy tarreaudfece232006-05-02 00:19:57 +02005261 } while (t->srv == NULL || t->conn_retries > 0 || !(t->proxy->options & PR_O_REDISP));
5262
5263 /* We're on our last chance, and the REDISP option was specified.
5264 * We will ignore cookie and force to balance or use the dispatcher.
5265 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005266 /* let's try to offer this slot to anybody */
5267 if (may_dequeue_tasks(t->srv, t->proxy))
5268 task_wakeup(&rq, t->srv->queue_mgt);
5269
willy tarreaudfece232006-05-02 00:19:57 +02005270 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
5271 t->srv = NULL; /* it's left to the dispatcher to choose a server */
5272 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
5273 t->flags &= ~SN_CK_MASK;
5274 t->flags |= SN_CK_DOWN;
5275 }
5276 return 0;
5277}
5278
5279/* This function performs the "redispatch" part of a connection attempt. It
5280 * will assign a server if required, queue the connection if required, and
5281 * handle errors that might arise at this level. It can change the server
5282 * state. It will return 1 if it encounters an error, switches the server
5283 * state, or has to queue a connection. Otherwise, it will return 0 indicating
5284 * that the connection is ready to use.
5285 */
5286
5287int srv_redispatch_connect(struct session *t) {
5288 int conn_err;
5289
5290 /* We know that we don't have any connection pending, so we will
5291 * try to get a new one, and wait in this state if it's queued
5292 */
5293 conn_err = assign_server_and_queue(t);
5294 switch (conn_err) {
5295 case SRV_STATUS_OK:
5296 break;
5297
5298 case SRV_STATUS_NOSRV:
willy tarreau59a6cc22006-05-12 01:29:08 +02005299 /* note: it is guaranteed that t->srv == NULL here */
willy tarreaudfece232006-05-02 00:19:57 +02005300 tv_eternity(&t->cnexpire);
5301 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
5302 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaudfece232006-05-02 00:19:57 +02005303 return 1;
5304
5305 case SRV_STATUS_QUEUED:
willy tarreau45526ed2006-05-03 20:11:50 +02005306 /* FIXME-20060503 : we should use the queue timeout instead */
5307 if (t->proxy->contimeout)
5308 tv_delayfrom(&t->cnexpire, &now, t->proxy->contimeout);
5309 else
5310 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02005311 t->srv_state = SV_STIDLE;
5312 /* do nothing else and do not wake any other session up */
5313 return 1;
5314
5315 case SRV_STATUS_FULL:
5316 case SRV_STATUS_INTERNAL:
5317 default:
5318 tv_eternity(&t->cnexpire);
5319 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
5320 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
5321 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02005322 if (may_dequeue_tasks(t->srv, t->proxy))
5323 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005324 return 1;
5325 }
5326 /* if we get here, it's because we got SRV_STATUS_OK, which also
5327 * means that the connection has not been queued.
5328 */
5329 return 0;
5330}
5331
5332
5333/*
willy tarreau0f7af912005-12-17 12:21:26 +01005334 * manages the server FSM and its socket. It returns 1 if a state has changed
5335 * (and a resync may be needed), 0 else.
5336 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005337int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01005338 int s = t->srv_state;
5339 int c = t->cli_state;
5340 struct buffer *req = t->req;
5341 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01005342 appsess *asession_temp = NULL;
5343 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01005344 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01005345
willy tarreau750a4722005-12-17 13:21:24 +01005346#ifdef DEBUG_FULL
5347 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
5348#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01005349 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
5350 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
5351 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
5352 //);
willy tarreau0f7af912005-12-17 12:21:26 +01005353 if (s == SV_STIDLE) {
5354 if (c == CL_STHEADERS)
5355 return 0; /* stay in idle, waiting for data to reach the client side */
5356 else if (c == CL_STCLOSE ||
5357 c == CL_STSHUTW ||
5358 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
5359 tv_eternity(&t->cnexpire);
willy tarreau424e04a2006-05-13 16:08:47 +02005360 if (t->pend_pos)
5361 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreau51e91292006-05-14 23:29:47 +02005362 /* note that this must not return any error because it would be able to
5363 * overwrite the client_retnclose() output.
5364 */
willy tarreau078c79a2006-05-13 12:23:58 +02005365 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 +02005366
willy tarreau0f7af912005-12-17 12:21:26 +01005367 return 1;
5368 }
willy tarreaudfece232006-05-02 00:19:57 +02005369 else {
5370 /* Right now, we will need to create a connection to the server.
5371 * We might already have tried, and got a connection pending, in
5372 * which case we will not do anything till it's pending. It's up
5373 * to any other session to release it and wake us up again.
5374 */
willy tarreau45526ed2006-05-03 20:11:50 +02005375 if (t->pend_pos) {
5376 if (tv_cmp2_ms(&t->cnexpire, &now) > 0)
5377 return 0;
5378 else {
5379 /* we've been waiting too long here */
5380 tv_eternity(&t->cnexpire);
willy tarreau078c79a2006-05-13 12:23:58 +02005381 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
5382 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
willy tarreau45526ed2006-05-03 20:11:50 +02005383 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
5384 return 1;
5385 }
5386 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005387
willy tarreaudfece232006-05-02 00:19:57 +02005388 do {
5389 /* first, get a connection */
5390 if (srv_redispatch_connect(t))
5391 return t->srv_state != SV_STIDLE;
5392
5393 /* try to (re-)connect to the server, and fail if we expire the
5394 * number of retries.
5395 */
willy tarreauf32f5242006-05-02 22:54:52 +02005396 if (srv_retryable_connect(t)) {
5397 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02005398 return t->srv_state != SV_STIDLE;
willy tarreauf32f5242006-05-02 22:54:52 +02005399 }
willy tarreaudfece232006-05-02 00:19:57 +02005400
5401 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01005402 }
5403 }
5404 else if (s == SV_STCONN) { /* connection in progress */
5405 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01005406 //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 +01005407 return 0; /* nothing changed */
5408 }
5409 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
willy tarreaudfece232006-05-02 00:19:57 +02005410 /* timeout, asynchronous connect error or first write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005411 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
willy tarreaudfece232006-05-02 00:19:57 +02005412
willy tarreau0f7af912005-12-17 12:21:26 +01005413 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005414 if (t->srv)
5415 t->srv->cur_sess--;
willy tarreaudfece232006-05-02 00:19:57 +02005416
5417 if (t->res_sw == RES_SILENT)
willy tarreaub1285d52005-12-18 01:20:14 +01005418 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
5419 else
willy tarreaudfece232006-05-02 00:19:57 +02005420 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
willy tarreaub1285d52005-12-18 01:20:14 +01005421
willy tarreaudfece232006-05-02 00:19:57 +02005422 /* ensure that we have enough retries left */
5423 if (srv_count_retry_down(t, conn_err))
5424 return 1;
5425
5426 do {
5427 /* Now we will try to either reconnect to the same server or
5428 * connect to another server. If the connection gets queued
5429 * because all servers are saturated, then we will go back to
5430 * the SV_STIDLE state.
5431 */
willy tarreauf32f5242006-05-02 22:54:52 +02005432 if (srv_retryable_connect(t)) {
5433 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02005434 return t->srv_state != SV_STCONN;
willy tarreauf32f5242006-05-02 22:54:52 +02005435 }
willy tarreaudfece232006-05-02 00:19:57 +02005436
5437 /* we need to redispatch the connection to another server */
5438 if (srv_redispatch_connect(t))
5439 return t->srv_state != SV_STCONN;
5440 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01005441 }
5442 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01005443 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005444
willy tarreau0f7af912005-12-17 12:21:26 +01005445 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005446 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01005447 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005448 tv_eternity(&t->swexpire);
5449 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01005450 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005451 if (t->proxy->srvtimeout) {
5452 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005453 /* FIXME: to prevent the server from expiring read timeouts during writes,
5454 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005455 t->srexpire = t->swexpire;
5456 }
5457 else
5458 tv_eternity(&t->swexpire);
5459 }
willy tarreau0f7af912005-12-17 12:21:26 +01005460
5461 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
5462 FD_SET(t->srv_fd, StaticReadEvent);
5463 if (t->proxy->srvtimeout)
5464 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5465 else
5466 tv_eternity(&t->srexpire);
5467
5468 t->srv_state = SV_STDATA;
willy tarreau2d505e52006-05-21 08:32:50 +02005469 if (t->srv)
5470 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01005471 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01005472
5473 /* if the user wants to log as soon as possible, without counting
5474 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005475 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005476 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
5477 sess_log(t);
5478 }
willy tarreau0f7af912005-12-17 12:21:26 +01005479 }
willy tarreauef900ab2005-12-17 12:52:52 +01005480 else {
willy tarreau0f7af912005-12-17 12:21:26 +01005481 t->srv_state = SV_STHEADERS;
willy tarreau2d505e52006-05-21 08:32:50 +02005482 if (t->srv)
5483 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01005484 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
5485 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005486 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005487 return 1;
5488 }
5489 }
5490 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005491 /* now parse the partial (or complete) headers */
5492 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
5493 char *ptr;
5494 int delete_header;
5495
5496 ptr = rep->lr;
5497
5498 /* look for the end of the current header */
5499 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
5500 ptr++;
5501
5502 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005503 int line, len;
5504
5505 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01005506
5507 /* first, we'll block if security checks have caught nasty things */
5508 if (t->flags & SN_CACHEABLE) {
5509 if ((t->flags & SN_CACHE_COOK) &&
5510 (t->flags & SN_SCK_ANY) &&
5511 (t->proxy->options & PR_O_CHK_CACHE)) {
5512
5513 /* we're in presence of a cacheable response containing
5514 * a set-cookie header. We'll block it as requested by
5515 * the 'checkcache' option, and send an alert.
5516 */
5517 tv_eternity(&t->srexpire);
5518 tv_eternity(&t->swexpire);
5519 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005520 if (t->srv)
5521 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01005522 t->srv_state = SV_STCLOSE;
5523 t->logs.status = 502;
5524 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
5525 if (!(t->flags & SN_ERR_MASK))
5526 t->flags |= SN_ERR_PRXCOND;
5527 if (!(t->flags & SN_FINST_MASK))
5528 t->flags |= SN_FINST_H;
5529
5530 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
5531 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
5532
willy tarreaudfece232006-05-02 00:19:57 +02005533 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005534 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005535 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005536 if (may_dequeue_tasks(t->srv, t->proxy))
5537 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005538
willy tarreau97f58572005-12-18 00:53:44 +01005539 return 1;
5540 }
5541 }
5542
willy tarreau982249e2005-12-18 00:57:06 +01005543 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
5544 if (t->flags & SN_SVDENY) {
5545 tv_eternity(&t->srexpire);
5546 tv_eternity(&t->swexpire);
5547 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005548 if (t->srv)
5549 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01005550 t->srv_state = SV_STCLOSE;
5551 t->logs.status = 502;
5552 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
5553 if (!(t->flags & SN_ERR_MASK))
5554 t->flags |= SN_ERR_PRXCOND;
5555 if (!(t->flags & SN_FINST_MASK))
5556 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005557 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005558 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005559 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005560 if (may_dequeue_tasks(t->srv, t->proxy))
5561 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005562
willy tarreau982249e2005-12-18 00:57:06 +01005563 return 1;
5564 }
5565
willy tarreau5cbea6f2005-12-17 12:48:26 +01005566 /* we'll have something else to do here : add new headers ... */
5567
willy tarreaucd878942005-12-17 13:27:43 +01005568 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
5569 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005570 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01005571 * insert a set-cookie here, except if we want to insert only on POST
willy tarreau4f7a1012006-05-09 23:32:26 +02005572 * requests and this one isn't. Note that servers which don't have cookies
5573 * (eg: some backup servers) will return a full cookie removal request.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005574 */
willy tarreau750a4722005-12-17 13:21:24 +01005575 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01005576 t->proxy->cookie_name,
willy tarreau4f7a1012006-05-09 23:32:26 +02005577 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
willy tarreau750a4722005-12-17 13:21:24 +01005578
willy tarreau036e1ce2005-12-17 13:46:33 +01005579 t->flags |= SN_SCK_INSERTED;
5580
willy tarreau750a4722005-12-17 13:21:24 +01005581 /* Here, we will tell an eventual cache on the client side that we don't
5582 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
5583 * Some caches understand the correct form: 'no-cache="set-cookie"', but
5584 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
5585 */
willy tarreau240afa62005-12-17 13:14:35 +01005586 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01005587 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
5588 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01005589
5590 if (rep->data + rep->l < rep->h)
5591 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
5592 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01005593 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005594 }
5595
5596 /* headers to be added */
5597 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01005598 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
5599 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005600 }
5601
willy tarreau25c4ea52005-12-18 00:49:49 +01005602 /* add a "connection: close" line if needed */
5603 if (t->proxy->options & PR_O_HTTP_CLOSE)
5604 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
5605
willy tarreau5cbea6f2005-12-17 12:48:26 +01005606 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01005607 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01005608 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01005609
Willy TARREAU767ba712006-03-01 22:40:50 +01005610 /* client connection already closed or option 'httpclose' required :
5611 * we close the server's outgoing connection right now.
5612 */
5613 if ((req->l == 0) &&
5614 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
5615 FD_CLR(t->srv_fd, StaticWriteEvent);
5616 tv_eternity(&t->swexpire);
5617
5618 /* We must ensure that the read part is still alive when switching
5619 * to shutw */
5620 FD_SET(t->srv_fd, StaticReadEvent);
5621 if (t->proxy->srvtimeout)
5622 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5623
5624 shutdown(t->srv_fd, SHUT_WR);
5625 t->srv_state = SV_STSHUTW;
5626 }
5627
willy tarreau25c4ea52005-12-18 00:49:49 +01005628 /* if the user wants to log as soon as possible, without counting
5629 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005630 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005631 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
5632 t->logs.bytes = rep->h - rep->data;
5633 sess_log(t);
5634 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005635 break;
5636 }
5637
5638 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
5639 if (ptr > rep->r - 2) {
5640 /* this is a partial header, let's wait for more to come */
5641 rep->lr = ptr;
5642 break;
5643 }
5644
5645 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
5646 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
5647
5648 /* now we know that *ptr is either \r or \n,
5649 * and that there are at least 1 char after it.
5650 */
5651 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
5652 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
5653 else
5654 rep->lr = ptr + 2; /* \r\n or \n\r */
5655
5656 /*
5657 * now we know that we have a full header ; we can do whatever
5658 * we want with these pointers :
5659 * rep->h = beginning of header
5660 * ptr = end of header (first \r or \n)
5661 * rep->lr = beginning of next line (next rep->h)
5662 * rep->r = end of data (not used at this stage)
5663 */
5664
willy tarreaua1598082005-12-17 13:08:06 +01005665
willy tarreau982249e2005-12-18 00:57:06 +01005666 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01005667 t->logs.logwait &= ~LW_RESP;
5668 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01005669 switch (t->logs.status) {
5670 case 200:
5671 case 203:
5672 case 206:
5673 case 300:
5674 case 301:
5675 case 410:
5676 /* RFC2616 @13.4:
5677 * "A response received with a status code of
5678 * 200, 203, 206, 300, 301 or 410 MAY be stored
5679 * by a cache (...) unless a cache-control
5680 * directive prohibits caching."
5681 *
5682 * RFC2616 @9.5: POST method :
5683 * "Responses to this method are not cacheable,
5684 * unless the response includes appropriate
5685 * Cache-Control or Expires header fields."
5686 */
5687 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
5688 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
5689 break;
5690 default:
5691 break;
5692 }
willy tarreau4302f492005-12-18 01:00:37 +01005693 }
5694 else if (t->logs.logwait & LW_RSPHDR) {
5695 struct cap_hdr *h;
5696 int len;
5697 for (h = t->proxy->rsp_cap; h; h = h->next) {
5698 if ((h->namelen + 2 <= ptr - rep->h) &&
5699 (rep->h[h->namelen] == ':') &&
5700 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
5701
5702 if (t->rsp_cap[h->index] == NULL)
5703 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
5704
5705 len = ptr - (rep->h + h->namelen + 2);
5706 if (len > h->len)
5707 len = h->len;
5708
5709 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
5710 t->rsp_cap[h->index][len]=0;
5711 }
5712 }
5713
willy tarreaua1598082005-12-17 13:08:06 +01005714 }
5715
willy tarreau5cbea6f2005-12-17 12:48:26 +01005716 delete_header = 0;
5717
willy tarreau982249e2005-12-18 00:57:06 +01005718 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005719 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01005720 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 +01005721 max = ptr - rep->h;
5722 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01005723 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005724 trash[len++] = '\n';
5725 write(1, trash, len);
5726 }
5727
willy tarreau25c4ea52005-12-18 00:49:49 +01005728 /* remove "connection: " if needed */
5729 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
5730 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
5731 delete_header = 1;
5732 }
5733
willy tarreau5cbea6f2005-12-17 12:48:26 +01005734 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01005735 if (!delete_header && t->proxy->rsp_exp != NULL
5736 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01005737 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005738 char term;
5739
5740 term = *ptr;
5741 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01005742 exp = t->proxy->rsp_exp;
5743 do {
5744 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
5745 switch (exp->action) {
5746 case ACT_ALLOW:
5747 if (!(t->flags & SN_SVDENY))
5748 t->flags |= SN_SVALLOW;
5749 break;
5750 case ACT_REPLACE:
5751 if (!(t->flags & SN_SVDENY)) {
5752 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
5753 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
5754 }
5755 break;
5756 case ACT_REMOVE:
5757 if (!(t->flags & SN_SVDENY))
5758 delete_header = 1;
5759 break;
5760 case ACT_DENY:
5761 if (!(t->flags & SN_SVALLOW))
5762 t->flags |= SN_SVDENY;
5763 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01005764 case ACT_PASS: /* we simply don't deny this one */
5765 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005766 }
5767 break;
5768 }
willy tarreaue39cd132005-12-17 13:00:18 +01005769 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005770 *ptr = term; /* restore the string terminator */
5771 }
5772
willy tarreau97f58572005-12-18 00:53:44 +01005773 /* check for cache-control: or pragma: headers */
5774 if (!delete_header && (t->flags & SN_CACHEABLE)) {
5775 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
5776 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5777 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
5778 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01005779 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01005780 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5781 else {
5782 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01005783 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005784 t->flags &= ~SN_CACHE_COOK;
5785 }
5786 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005787 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005788 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005789 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01005790 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5791 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005792 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01005793 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01005794 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
5795 (rep->h + 25 == ptr || rep->h[25] == ',')) {
5796 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5797 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
5798 (rep->h + 21 == ptr || rep->h[21] == ',')) {
5799 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01005800 }
5801 }
5802 }
5803
willy tarreau5cbea6f2005-12-17 12:48:26 +01005804 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01005805 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01005806 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01005807 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005808 char *p1, *p2, *p3, *p4;
5809
willy tarreau97f58572005-12-18 00:53:44 +01005810 t->flags |= SN_SCK_ANY;
5811
willy tarreau5cbea6f2005-12-17 12:48:26 +01005812 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
5813
5814 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01005815 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005816 p1++;
5817
5818 if (p1 == ptr || *p1 == ';') /* end of cookie */
5819 break;
5820
5821 /* p1 is at the beginning of the cookie name */
5822 p2 = p1;
5823
5824 while (p2 < ptr && *p2 != '=' && *p2 != ';')
5825 p2++;
5826
5827 if (p2 == ptr || *p2 == ';') /* next cookie */
5828 break;
5829
5830 p3 = p2 + 1; /* skips the '=' sign */
5831 if (p3 == ptr)
5832 break;
5833
5834 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01005835 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01005836 p4++;
5837
5838 /* here, we have the cookie name between p1 and p2,
5839 * and its value between p3 and p4.
5840 * we can process it.
5841 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005842
5843 /* first, let's see if we want to capture it */
5844 if (t->proxy->capture_name != NULL &&
5845 t->logs.srv_cookie == NULL &&
5846 (p4 - p1 >= t->proxy->capture_namelen) &&
5847 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
5848 int log_len = p4 - p1;
5849
5850 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
5851 Alert("HTTP logging : out of memory.\n");
5852 }
5853
5854 if (log_len > t->proxy->capture_len)
5855 log_len = t->proxy->capture_len;
5856 memcpy(t->logs.srv_cookie, p1, log_len);
5857 t->logs.srv_cookie[log_len] = 0;
5858 }
5859
5860 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
5861 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005862 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01005863 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005864
5865 /* If the cookie is in insert mode on a known server, we'll delete
5866 * this occurrence because we'll insert another one later.
5867 * We'll delete it too if the "indirect" option is set and we're in
5868 * a direct access. */
5869 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01005870 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005871 /* this header must be deleted */
5872 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01005873 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005874 }
5875 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
5876 /* replace bytes p3->p4 with the cookie name associated
5877 * with this server since we know it.
5878 */
5879 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01005880 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005881 }
willy tarreau0174f312005-12-18 01:02:42 +01005882 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
5883 /* insert the cookie name associated with this server
5884 * before existing cookie, and insert a delimitor between them..
5885 */
5886 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
5887 p3[t->srv->cklen] = COOKIE_DELIM;
5888 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
5889 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005890 break;
5891 }
willy tarreau12350152005-12-18 01:03:27 +01005892
5893 /* first, let's see if the cookie is our appcookie*/
5894 if ((t->proxy->appsession_name != NULL) &&
5895 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
5896
5897 /* Cool... it's the right one */
5898
willy tarreaub952e1d2005-12-18 01:31:20 +01005899 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01005900 asession_temp = &local_asession;
5901
willy tarreaub952e1d2005-12-18 01:31:20 +01005902 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005903 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5904 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5905 }
5906 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
5907 asession_temp->sessid[t->proxy->appsession_len] = 0;
5908 asession_temp->serverid = NULL;
5909
5910 /* only do insert, if lookup fails */
5911 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
5912 if ((asession_temp = pool_alloc(appsess)) == NULL) {
5913 Alert("Not enought Memory process_srv():asession:calloc().\n");
5914 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
5915 return 0;
5916 }
5917 asession_temp->sessid = local_asession.sessid;
5918 asession_temp->serverid = local_asession.serverid;
5919 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01005920 }/* end if (chtbl_lookup()) */
5921 else {
willy tarreau12350152005-12-18 01:03:27 +01005922 /* free wasted memory */
5923 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01005924 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01005925
willy tarreaub952e1d2005-12-18 01:31:20 +01005926 if (asession_temp->serverid == NULL) {
5927 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005928 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5929 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5930 }
5931 asession_temp->serverid[0] = '\0';
5932 }
5933
willy tarreaub952e1d2005-12-18 01:31:20 +01005934 if (asession_temp->serverid[0] == '\0')
5935 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01005936
5937 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
5938
5939#if defined(DEBUG_HASH)
5940 print_table(&(t->proxy->htbl_proxy));
5941#endif
5942 break;
5943 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005944 else {
5945 // fprintf(stderr,"Ignoring unknown cookie : ");
5946 // write(2, p1, p2-p1);
5947 // fprintf(stderr," = ");
5948 // write(2, p3, p4-p3);
5949 // fprintf(stderr,"\n");
5950 }
5951 break; /* we don't want to loop again since there cannot be another cookie on the same line */
5952 } /* we're now at the end of the cookie value */
5953 } /* end of cookie processing */
5954
willy tarreau97f58572005-12-18 00:53:44 +01005955 /* check for any set-cookie in case we check for cacheability */
5956 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
5957 (t->proxy->options & PR_O_CHK_CACHE) &&
5958 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
5959 t->flags |= SN_SCK_ANY;
5960 }
5961
willy tarreau5cbea6f2005-12-17 12:48:26 +01005962 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01005963 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005964 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01005965
willy tarreau5cbea6f2005-12-17 12:48:26 +01005966 rep->h = rep->lr;
5967 } /* while (rep->lr < rep->r) */
5968
5969 /* end of header processing (even if incomplete) */
5970
willy tarreauef900ab2005-12-17 12:52:52 +01005971 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5972 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
5973 * full. We cannot loop here since event_srv_read will disable it only if
5974 * rep->l == rlim-data
5975 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005976 FD_SET(t->srv_fd, StaticReadEvent);
5977 if (t->proxy->srvtimeout)
5978 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5979 else
5980 tv_eternity(&t->srexpire);
5981 }
willy tarreau0f7af912005-12-17 12:21:26 +01005982
willy tarreau8337c6b2005-12-17 13:41:01 +01005983 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005984 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005985 tv_eternity(&t->srexpire);
5986 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005987 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005988 if (t->srv)
5989 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005990 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01005991 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01005992 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01005993 if (!(t->flags & SN_ERR_MASK))
5994 t->flags |= SN_ERR_SRVCL;
5995 if (!(t->flags & SN_FINST_MASK))
5996 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005997 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005998 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005999 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006000 if (may_dequeue_tasks(t->srv, t->proxy))
6001 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006002
willy tarreau0f7af912005-12-17 12:21:26 +01006003 return 1;
6004 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006005 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01006006 * since we are in header mode, if there's no space left for headers, we
6007 * won't be able to free more later, so the session will never terminate.
6008 */
willy tarreau8337c6b2005-12-17 13:41:01 +01006009 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 +01006010 FD_CLR(t->srv_fd, StaticReadEvent);
6011 tv_eternity(&t->srexpire);
6012 shutdown(t->srv_fd, SHUT_RD);
6013 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01006014 //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 +01006015 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006016 }
6017 /* read timeout : return a 504 to the client.
6018 */
6019 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6020 tv_eternity(&t->srexpire);
6021 tv_eternity(&t->swexpire);
6022 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006023 if (t->srv)
6024 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01006025 t->srv_state = SV_STCLOSE;
6026 t->logs.status = 504;
6027 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01006028 if (!(t->flags & SN_ERR_MASK))
6029 t->flags |= SN_ERR_SRVTO;
6030 if (!(t->flags & SN_FINST_MASK))
6031 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02006032 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006033 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006034 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006035 if (may_dequeue_tasks(t->srv, t->proxy))
6036 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006037
willy tarreau8337c6b2005-12-17 13:41:01 +01006038 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006039 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006040 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01006041 /* FIXME!!! here, we don't want to switch to SHUTW if the
6042 * client shuts read too early, because we may still have
6043 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01006044 * The side-effect is that if the client completely closes its
6045 * connection during SV_STHEADER, the connection to the server
6046 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01006047 */
willy tarreau036e1ce2005-12-17 13:46:33 +01006048 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01006049 FD_CLR(t->srv_fd, StaticWriteEvent);
6050 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01006051
6052 /* We must ensure that the read part is still alive when switching
6053 * to shutw */
6054 FD_SET(t->srv_fd, StaticReadEvent);
6055 if (t->proxy->srvtimeout)
6056 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6057
willy tarreau0f7af912005-12-17 12:21:26 +01006058 shutdown(t->srv_fd, SHUT_WR);
6059 t->srv_state = SV_STSHUTW;
6060 return 1;
6061 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006062 /* write timeout */
6063 /* FIXME!!! here, we don't want to switch to SHUTW if the
6064 * client shuts read too early, because we may still have
6065 * some work to do on the headers.
6066 */
6067 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
6068 FD_CLR(t->srv_fd, StaticWriteEvent);
6069 tv_eternity(&t->swexpire);
6070 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006071 /* We must ensure that the read part is still alive when switching
6072 * to shutw */
6073 FD_SET(t->srv_fd, StaticReadEvent);
6074 if (t->proxy->srvtimeout)
6075 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6076
6077 /* We must ensure that the read part is still alive when switching
6078 * to shutw */
6079 FD_SET(t->srv_fd, StaticReadEvent);
6080 if (t->proxy->srvtimeout)
6081 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6082
willy tarreau036e1ce2005-12-17 13:46:33 +01006083 t->srv_state = SV_STSHUTW;
6084 if (!(t->flags & SN_ERR_MASK))
6085 t->flags |= SN_ERR_SRVTO;
6086 if (!(t->flags & SN_FINST_MASK))
6087 t->flags |= SN_FINST_H;
6088 return 1;
6089 }
willy tarreau0f7af912005-12-17 12:21:26 +01006090
6091 if (req->l == 0) {
6092 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6093 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6094 tv_eternity(&t->swexpire);
6095 }
6096 }
6097 else { /* client buffer not empty */
6098 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6099 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006100 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006101 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006102 /* FIXME: to prevent the server from expiring read timeouts during writes,
6103 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006104 t->srexpire = t->swexpire;
6105 }
willy tarreau0f7af912005-12-17 12:21:26 +01006106 else
6107 tv_eternity(&t->swexpire);
6108 }
6109 }
6110
willy tarreau5cbea6f2005-12-17 12:48:26 +01006111 /* be nice with the client side which would like to send a complete header
6112 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
6113 * would read all remaining data at once ! The client should not write past rep->lr
6114 * when the server is in header state.
6115 */
6116 //return header_processed;
6117 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01006118 }
6119 else if (s == SV_STDATA) {
6120 /* read or write error */
6121 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01006122 tv_eternity(&t->srexpire);
6123 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006124 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006125 if (t->srv)
6126 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01006127 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01006128 if (!(t->flags & SN_ERR_MASK))
6129 t->flags |= SN_ERR_SRVCL;
6130 if (!(t->flags & SN_FINST_MASK))
6131 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006132 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006133 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006134 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006135 if (may_dequeue_tasks(t->srv, t->proxy))
6136 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006137
willy tarreau0f7af912005-12-17 12:21:26 +01006138 return 1;
6139 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006140 /* last read, or end of client write */
6141 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01006142 FD_CLR(t->srv_fd, StaticReadEvent);
6143 tv_eternity(&t->srexpire);
6144 shutdown(t->srv_fd, SHUT_RD);
6145 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01006146 //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 +01006147 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01006148 }
6149 /* end of client read and no more data to send */
6150 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
6151 FD_CLR(t->srv_fd, StaticWriteEvent);
6152 tv_eternity(&t->swexpire);
6153 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006154 /* We must ensure that the read part is still alive when switching
6155 * to shutw */
6156 FD_SET(t->srv_fd, StaticReadEvent);
6157 if (t->proxy->srvtimeout)
6158 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6159
willy tarreaua41a8b42005-12-17 14:02:24 +01006160 t->srv_state = SV_STSHUTW;
6161 return 1;
6162 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006163 /* read timeout */
6164 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6165 FD_CLR(t->srv_fd, StaticReadEvent);
6166 tv_eternity(&t->srexpire);
6167 shutdown(t->srv_fd, SHUT_RD);
6168 t->srv_state = SV_STSHUTR;
6169 if (!(t->flags & SN_ERR_MASK))
6170 t->flags |= SN_ERR_SRVTO;
6171 if (!(t->flags & SN_FINST_MASK))
6172 t->flags |= SN_FINST_D;
6173 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006174 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006175 /* write timeout */
6176 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01006177 FD_CLR(t->srv_fd, StaticWriteEvent);
6178 tv_eternity(&t->swexpire);
6179 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006180 /* We must ensure that the read part is still alive when switching
6181 * to shutw */
6182 FD_SET(t->srv_fd, StaticReadEvent);
6183 if (t->proxy->srvtimeout)
6184 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01006185 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01006186 if (!(t->flags & SN_ERR_MASK))
6187 t->flags |= SN_ERR_SRVTO;
6188 if (!(t->flags & SN_FINST_MASK))
6189 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01006190 return 1;
6191 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01006192
6193 /* recompute request time-outs */
6194 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01006195 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6196 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6197 tv_eternity(&t->swexpire);
6198 }
6199 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01006200 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01006201 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6202 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006203 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006204 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006205 /* FIXME: to prevent the server from expiring read timeouts during writes,
6206 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006207 t->srexpire = t->swexpire;
6208 }
willy tarreau0f7af912005-12-17 12:21:26 +01006209 else
6210 tv_eternity(&t->swexpire);
6211 }
6212 }
6213
willy tarreaub1ff9db2005-12-17 13:51:03 +01006214 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01006215 if (rep->l == BUFSIZE) { /* no room to read more data */
6216 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
6217 FD_CLR(t->srv_fd, StaticReadEvent);
6218 tv_eternity(&t->srexpire);
6219 }
6220 }
6221 else {
6222 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6223 FD_SET(t->srv_fd, StaticReadEvent);
6224 if (t->proxy->srvtimeout)
6225 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6226 else
6227 tv_eternity(&t->srexpire);
6228 }
6229 }
6230
6231 return 0; /* other cases change nothing */
6232 }
6233 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006234 if (t->res_sw == RES_ERROR) {
6235 //FD_CLR(t->srv_fd, StaticWriteEvent);
6236 tv_eternity(&t->swexpire);
6237 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006238 if (t->srv)
6239 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006240 //close(t->srv_fd);
6241 t->srv_state = SV_STCLOSE;
6242 if (!(t->flags & SN_ERR_MASK))
6243 t->flags |= SN_ERR_SRVCL;
6244 if (!(t->flags & SN_FINST_MASK))
6245 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006246 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006247 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006248 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006249 if (may_dequeue_tasks(t->srv, t->proxy))
6250 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006251
willy tarreau036e1ce2005-12-17 13:46:33 +01006252 return 1;
6253 }
6254 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006255 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01006256 tv_eternity(&t->swexpire);
6257 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006258 if (t->srv)
6259 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006260 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01006261 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02006262 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006263 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006264 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006265 if (may_dequeue_tasks(t->srv, t->proxy))
6266 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006267
willy tarreau0f7af912005-12-17 12:21:26 +01006268 return 1;
6269 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006270 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
6271 //FD_CLR(t->srv_fd, StaticWriteEvent);
6272 tv_eternity(&t->swexpire);
6273 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006274 if (t->srv)
6275 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006276 //close(t->srv_fd);
6277 t->srv_state = SV_STCLOSE;
6278 if (!(t->flags & SN_ERR_MASK))
6279 t->flags |= SN_ERR_SRVTO;
6280 if (!(t->flags & SN_FINST_MASK))
6281 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006282 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006283 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006284 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006285 if (may_dequeue_tasks(t->srv, t->proxy))
6286 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006287
willy tarreau036e1ce2005-12-17 13:46:33 +01006288 return 1;
6289 }
willy tarreau0f7af912005-12-17 12:21:26 +01006290 else if (req->l == 0) {
6291 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6292 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6293 tv_eternity(&t->swexpire);
6294 }
6295 }
6296 else { /* buffer not empty */
6297 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6298 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006299 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006300 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006301 /* FIXME: to prevent the server from expiring read timeouts during writes,
6302 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006303 t->srexpire = t->swexpire;
6304 }
willy tarreau0f7af912005-12-17 12:21:26 +01006305 else
6306 tv_eternity(&t->swexpire);
6307 }
6308 }
6309 return 0;
6310 }
6311 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006312 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006313 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01006314 tv_eternity(&t->srexpire);
6315 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006316 if (t->srv)
6317 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006318 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01006319 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01006320 if (!(t->flags & SN_ERR_MASK))
6321 t->flags |= SN_ERR_SRVCL;
6322 if (!(t->flags & SN_FINST_MASK))
6323 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006324 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006325 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006326 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006327 if (may_dequeue_tasks(t->srv, t->proxy))
6328 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006329
willy tarreau0f7af912005-12-17 12:21:26 +01006330 return 1;
6331 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006332 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
6333 //FD_CLR(t->srv_fd, StaticReadEvent);
6334 tv_eternity(&t->srexpire);
6335 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006336 if (t->srv)
6337 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006338 //close(t->srv_fd);
6339 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02006340 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006341 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006342 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006343 if (may_dequeue_tasks(t->srv, t->proxy))
6344 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006345
willy tarreau036e1ce2005-12-17 13:46:33 +01006346 return 1;
6347 }
6348 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6349 //FD_CLR(t->srv_fd, StaticReadEvent);
6350 tv_eternity(&t->srexpire);
6351 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006352 if (t->srv)
6353 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006354 //close(t->srv_fd);
6355 t->srv_state = SV_STCLOSE;
6356 if (!(t->flags & SN_ERR_MASK))
6357 t->flags |= SN_ERR_SRVTO;
6358 if (!(t->flags & SN_FINST_MASK))
6359 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006360 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006361 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006362 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006363 if (may_dequeue_tasks(t->srv, t->proxy))
6364 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006365
willy tarreau036e1ce2005-12-17 13:46:33 +01006366 return 1;
6367 }
willy tarreau0f7af912005-12-17 12:21:26 +01006368 else if (rep->l == BUFSIZE) { /* no room to read more data */
6369 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
6370 FD_CLR(t->srv_fd, StaticReadEvent);
6371 tv_eternity(&t->srexpire);
6372 }
6373 }
6374 else {
6375 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6376 FD_SET(t->srv_fd, StaticReadEvent);
6377 if (t->proxy->srvtimeout)
6378 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6379 else
6380 tv_eternity(&t->srexpire);
6381 }
6382 }
6383 return 0;
6384 }
6385 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01006386 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01006387 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01006388 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 +01006389 write(1, trash, len);
6390 }
6391 return 0;
6392 }
6393 return 0;
6394}
6395
6396
willy tarreau5cbea6f2005-12-17 12:48:26 +01006397/* Processes the client and server jobs of a session task, then
6398 * puts it back to the wait queue in a clean state, or
6399 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01006400 * the time the task accepts to wait, or TIME_ETERNITY for
6401 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01006402 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006403int process_session(struct task *t) {
6404 struct session *s = t->context;
6405 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006406
willy tarreau5cbea6f2005-12-17 12:48:26 +01006407 do {
6408 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01006409 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006410 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01006411 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006412 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01006413 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006414 } while (fsm_resync);
6415
6416 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01006417 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006418 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01006419
willy tarreau5cbea6f2005-12-17 12:48:26 +01006420 tv_min(&min1, &s->crexpire, &s->cwexpire);
6421 tv_min(&min2, &s->srexpire, &s->swexpire);
6422 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01006423 tv_min(&t->expire, &min1, &min2);
6424
6425 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006426 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01006427
Willy TARREAU1cec83c2006-03-01 22:33:49 +01006428#ifdef DEBUG_FULL
6429 /* DEBUG code : this should never ever happen, otherwise it indicates
6430 * that a task still has something to do and will provoke a quick loop.
6431 */
6432 if (tv_remain2(&now, &t->expire) <= 0)
6433 exit(100);
6434#endif
6435
willy tarreaub952e1d2005-12-18 01:31:20 +01006436 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01006437 }
6438
willy tarreau5cbea6f2005-12-17 12:48:26 +01006439 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01006440 actconn--;
6441
willy tarreau982249e2005-12-18 00:57:06 +01006442 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01006443 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01006444 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 +01006445 write(1, trash, len);
6446 }
6447
willy tarreau750a4722005-12-17 13:21:24 +01006448 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01006449 if (s->rep != NULL)
6450 s->logs.bytes = s->rep->total;
6451
willy tarreau9fe663a2005-12-17 13:02:59 +01006452 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01006453 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01006454 sess_log(s);
6455
willy tarreau0f7af912005-12-17 12:21:26 +01006456 /* the task MUST not be in the run queue anymore */
6457 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006458 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01006459 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01006460 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006461}
6462
6463
willy tarreau2812edc2006-05-04 12:09:37 +02006464/* Sets server <s> down, notifies by all available means, recounts the
6465 * remaining servers on the proxy and transfers queued sessions whenever
6466 * possible to other servers.
6467 */
6468void set_server_down(struct server *s) {
6469 struct pendconn *pc, *pc_bck, *pc_end;
6470 struct session *sess;
6471 int xferred;
6472
6473 s->state &= ~SRV_RUNNING;
6474
6475 if (s->health == s->rise) {
6476 recount_servers(s->proxy);
6477 recalc_server_map(s->proxy);
6478
6479 /* we might have sessions queued on this server and waiting for
6480 * a connection. Those which are redispatchable will be queued
6481 * to another server or to the proxy itself.
6482 */
6483 xferred = 0;
6484 FOREACH_ITEM_SAFE(pc, pc_bck, &s->pendconns, pc_end, struct pendconn *, list) {
6485 sess = pc->sess;
6486 if ((sess->proxy->options & PR_O_REDISP)) {
6487 /* The REDISP option was specified. We will ignore
6488 * cookie and force to balance or use the dispatcher.
6489 */
6490 sess->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
6491 sess->srv = NULL; /* it's left to the dispatcher to choose a server */
6492 if ((sess->flags & SN_CK_MASK) == SN_CK_VALID) {
6493 sess->flags &= ~SN_CK_MASK;
6494 sess->flags |= SN_CK_DOWN;
6495 }
6496 pendconn_free(pc);
6497 task_wakeup(&rq, sess->task);
6498 xferred++;
6499 }
6500 }
6501
6502 sprintf(trash, "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s"
6503 " %d sessions active, %d requeued, %d remaining in queue.\n",
6504 s->state & SRV_BACKUP ? "Backup " : "",
6505 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6506 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6507 s->cur_sess, xferred, s->nbpend);
6508
willy tarreaubc2eda62006-05-04 15:16:23 +02006509 Warning("%s", trash);
6510 send_log(s->proxy, LOG_ALERT, "%s", trash);
willy tarreau2812edc2006-05-04 12:09:37 +02006511
6512 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
6513 Alert("Proxy %s has no server available !\n", s->proxy->id);
6514 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
6515 }
willy tarreaucb406512006-05-18 00:52:35 +02006516 s->down_trans++;
willy tarreau2812edc2006-05-04 12:09:37 +02006517 }
6518 s->health = 0; /* failure */
6519}
6520
6521
willy tarreau5cbea6f2005-12-17 12:48:26 +01006522
6523/*
6524 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01006525 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01006526 */
6527int process_chk(struct task *t) {
6528 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01006529 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01006530 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006531
willy tarreauef900ab2005-12-17 12:52:52 +01006532 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006533
willy tarreau25424f82006-03-19 19:37:48 +01006534 new_chk:
6535 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006536 if (fd < 0) { /* no check currently running */
6537 //fprintf(stderr, "process_chk: 2\n");
6538 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
6539 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006540 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006541 }
Willy TARREAU3759f982006-03-01 22:44:17 +01006542
6543 /* we don't send any health-checks when the proxy is stopped or when
6544 * the server should not be checked.
6545 */
6546 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01006547 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6548 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01006549 task_queue(t); /* restore t to its place in the task list */
6550 return tv_remain2(&now, &t->expire);
6551 }
6552
willy tarreau5cbea6f2005-12-17 12:48:26 +01006553 /* we'll initiate a new check */
6554 s->result = 0; /* no result yet */
6555 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006556 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01006557 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
6558 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
6559 //fprintf(stderr, "process_chk: 3\n");
6560
willy tarreaua41a8b42005-12-17 14:02:24 +01006561 /* we'll connect to the check port on the server */
6562 sa = s->addr;
6563 sa.sin_port = htons(s->check_port);
6564
willy tarreau0174f312005-12-18 01:02:42 +01006565 /* allow specific binding :
6566 * - server-specific at first
6567 * - proxy-specific next
6568 */
6569 if (s->state & SRV_BIND_SRC) {
6570 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
6571 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
6572 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
6573 s->proxy->id, s->id);
6574 s->result = -1;
6575 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006576 }
willy tarreau0174f312005-12-18 01:02:42 +01006577 else if (s->proxy->options & PR_O_BIND_SRC) {
6578 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
6579 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
6580 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
6581 s->proxy->id);
6582 s->result = -1;
6583 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006584 }
willy tarreau0174f312005-12-18 01:02:42 +01006585
6586 if (!s->result) {
6587 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
6588 /* OK, connection in progress or established */
6589
6590 //fprintf(stderr, "process_chk: 4\n");
6591
6592 s->curfd = fd; /* that's how we know a test is in progress ;-) */
6593 fdtab[fd].owner = t;
6594 fdtab[fd].read = &event_srv_chk_r;
6595 fdtab[fd].write = &event_srv_chk_w;
6596 fdtab[fd].state = FD_STCONN; /* connection in progress */
6597 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01006598#ifdef DEBUG_FULL
6599 assert (!FD_ISSET(fd, StaticReadEvent));
6600#endif
willy tarreau0174f312005-12-18 01:02:42 +01006601 fd_insert(fd);
6602 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
6603 tv_delayfrom(&t->expire, &now, s->inter);
6604 task_queue(t); /* restore t to its place in the task list */
6605 return tv_remain(&now, &t->expire);
6606 }
6607 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
6608 s->result = -1; /* a real error */
6609 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006610 }
6611 }
willy tarreau08dedbe2005-12-18 01:13:48 +01006612 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006613 }
6614
6615 if (!s->result) { /* nothing done */
6616 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01006617 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6618 tv_delayfrom(&t->expire, &t->expire, s->inter);
6619 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006620 }
6621
6622 /* here, we have seen a failure */
willy tarreaucb406512006-05-18 00:52:35 +02006623 if (s->health > s->rise) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006624 s->health--; /* still good */
willy tarreaucb406512006-05-18 00:52:35 +02006625 s->failed_checks++;
6626 }
willy tarreau2812edc2006-05-04 12:09:37 +02006627 else
6628 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006629
6630 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01006631 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01006632 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6633 tv_delayfrom(&t->expire, &t->expire, s->inter);
6634 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006635 }
6636 else {
6637 //fprintf(stderr, "process_chk: 8\n");
6638 /* there was a test running */
6639 if (s->result > 0) { /* good server detected */
6640 //fprintf(stderr, "process_chk: 9\n");
6641 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01006642 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02006643 s->state |= SRV_RUNNING;
6644
willy tarreau535ae7a2005-12-17 12:58:00 +01006645 if (s->health == s->rise) {
willy tarreaubc2eda62006-05-04 15:16:23 +02006646 int xferred;
6647
willy tarreau62084d42006-03-24 18:57:41 +01006648 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02006649 recalc_server_map(s->proxy);
willy tarreaubc2eda62006-05-04 15:16:23 +02006650
6651 /* check if we can handle some connections queued at the proxy. We
6652 * will take as many as we can handle.
6653 */
6654 for (xferred = 0; !s->maxconn || xferred < s->maxconn; xferred++) {
6655 struct session *sess;
6656 struct pendconn *p;
6657
6658 p = pendconn_from_px(s->proxy);
6659 if (!p)
6660 break;
6661 p->sess->srv = s;
6662 sess = p->sess;
6663 pendconn_free(p);
6664 task_wakeup(&rq, sess->task);
6665 }
6666
6667 sprintf(trash,
6668 "%sServer %s/%s is UP. %d active and %d backup servers online.%s"
6669 " %d sessions requeued, %d total in queue.\n",
6670 s->state & SRV_BACKUP ? "Backup " : "",
6671 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6672 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6673 xferred, s->nbpend);
6674
6675 Warning("%s", trash);
6676 send_log(s->proxy, LOG_NOTICE, "%s", trash);
willy tarreau535ae7a2005-12-17 12:58:00 +01006677 }
willy tarreauef900ab2005-12-17 12:52:52 +01006678
willy tarreaue47c8d72005-12-17 12:55:52 +01006679 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006680 }
willy tarreauef900ab2005-12-17 12:52:52 +01006681 s->curfd = -1; /* no check running anymore */
6682 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006683 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006684 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6685 tv_delayfrom(&t->expire, &t->expire, s->inter);
6686 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006687 }
6688 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
6689 //fprintf(stderr, "process_chk: 10\n");
6690 /* failure or timeout detected */
willy tarreaucb406512006-05-18 00:52:35 +02006691 if (s->health > s->rise) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006692 s->health--; /* still good */
willy tarreaucb406512006-05-18 00:52:35 +02006693 s->failed_checks++;
6694 }
willy tarreau2812edc2006-05-04 12:09:37 +02006695 else
6696 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006697 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01006698 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006699 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006700 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6701 tv_delayfrom(&t->expire, &t->expire, s->inter);
6702 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006703 }
6704 /* if result is 0 and there's no timeout, we have to wait again */
6705 }
6706 //fprintf(stderr, "process_chk: 11\n");
6707 s->result = 0;
6708 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006709 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01006710}
6711
6712
willy tarreau5cbea6f2005-12-17 12:48:26 +01006713
willy tarreau59a6cc22006-05-12 01:29:08 +02006714/*
6715 * Manages a server's connection queue. If woken up, will try to dequeue as
6716 * many pending sessions as possible, and wake them up. The task has nothing
6717 * else to do, so it always returns TIME_ETERNITY.
6718 */
6719int process_srv_queue(struct task *t) {
6720 struct server *s = (struct server*)t->context;
6721 struct proxy *p = s->proxy;
6722 int xferred;
6723
6724 /* First, check if we can handle some connections queued at the proxy. We
6725 * will take as many as we can handle.
6726 */
6727 for (xferred = 0; s->cur_sess + xferred < s->maxconn; xferred++) {
6728 struct session *sess;
6729
6730 sess = pendconn_get_next_sess(s, p);
6731 if (sess == NULL)
6732 break;
6733 task_wakeup(&rq, sess->task);
6734 }
6735
6736 return TIME_ETERNITY;
6737}
6738
willy tarreau0f7af912005-12-17 12:21:26 +01006739#if STATTIME > 0
6740int stats(void);
6741#endif
6742
6743/*
willy tarreau1c2ad212005-12-18 01:11:29 +01006744 * This does 4 things :
6745 * - wake up all expired tasks
6746 * - call all runnable tasks
6747 * - call maintain_proxies() to enable/disable the listeners
6748 * - return the delay till next event in ms, -1 = wait indefinitely
6749 * Note: this part should be rewritten with the O(ln(n)) scheduler.
6750 *
willy tarreau0f7af912005-12-17 12:21:26 +01006751 */
6752
willy tarreau1c2ad212005-12-18 01:11:29 +01006753int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01006754 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01006755 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006756 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01006757
willy tarreaub952e1d2005-12-18 01:31:20 +01006758 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01006759
willy tarreau1c2ad212005-12-18 01:11:29 +01006760 /* look for expired tasks and add them to the run queue.
6761 */
willy tarreau5e698ef2006-05-02 14:51:00 +02006762 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6763 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau1c2ad212005-12-18 01:11:29 +01006764 tnext = t->next;
6765 if (t->state & TASK_RUNNING)
6766 continue;
6767
willy tarreaub952e1d2005-12-18 01:31:20 +01006768 if (tv_iseternity(&t->expire))
6769 continue;
6770
willy tarreau1c2ad212005-12-18 01:11:29 +01006771 /* wakeup expired entries. It doesn't matter if they are
6772 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01006773 */
willy tarreaub952e1d2005-12-18 01:31:20 +01006774 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006775 task_wakeup(&rq, t);
6776 }
6777 else {
6778 /* first non-runnable task. Use its expiration date as an upper bound */
6779 int temp_time = tv_remain(&now, &t->expire);
6780 if (temp_time)
6781 next_time = temp_time;
6782 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006783 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006784 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006785
willy tarreau1c2ad212005-12-18 01:11:29 +01006786 /* process each task in the run queue now. Each task may be deleted
willy tarreau7feab592006-04-22 15:13:16 +02006787 * since we only use the run queue's head. Note that any task can be
6788 * woken up by any other task and it will be processed immediately
6789 * after as it will be queued on the run queue's head.
willy tarreau1c2ad212005-12-18 01:11:29 +01006790 */
willy tarreau7feab592006-04-22 15:13:16 +02006791 while ((t = rq) != NULL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006792 int temp_time;
willy tarreau7feab592006-04-22 15:13:16 +02006793
willy tarreau1c2ad212005-12-18 01:11:29 +01006794 task_sleep(&rq, t);
6795 temp_time = t->process(t);
6796 next_time = MINTIME(temp_time, next_time);
6797 }
6798
6799 /* maintain all proxies in a consistent state. This should quickly become a task */
6800 time2 = maintain_proxies();
6801 return MINTIME(time2, next_time);
6802}
6803
6804
6805#if defined(ENABLE_EPOLL)
6806
6807/*
6808 * Main epoll() loop.
6809 */
6810
6811/* does 3 actions :
6812 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6813 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6814 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6815 *
6816 * returns 0 if initialization failed, !0 otherwise.
6817 */
6818
6819int epoll_loop(int action) {
6820 int next_time;
6821 int status;
6822 int fd;
6823
6824 int fds, count;
6825 int pr, pw, sr, sw;
6826 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
6827 struct epoll_event ev;
6828
6829 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01006830 static struct epoll_event *epoll_events = NULL;
6831 static int epoll_fd;
6832
6833 if (action == POLL_LOOP_ACTION_INIT) {
6834 epoll_fd = epoll_create(global.maxsock + 1);
6835 if (epoll_fd < 0)
6836 return 0;
6837 else {
6838 epoll_events = (struct epoll_event*)
6839 calloc(1, sizeof(struct epoll_event) * global.maxsock);
6840 PrevReadEvent = (fd_set *)
6841 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6842 PrevWriteEvent = (fd_set *)
6843 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006844 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006845 return 1;
6846 }
6847 else if (action == POLL_LOOP_ACTION_CLEAN) {
6848 if (PrevWriteEvent) free(PrevWriteEvent);
6849 if (PrevReadEvent) free(PrevReadEvent);
6850 if (epoll_events) free(epoll_events);
6851 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01006852 epoll_fd = 0;
6853 return 1;
6854 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006855
willy tarreau1c2ad212005-12-18 01:11:29 +01006856 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006857
willy tarreau1c2ad212005-12-18 01:11:29 +01006858 tv_now(&now);
6859
6860 while (1) {
6861 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01006862
6863 /* stop when there's no connection left and we don't allow them anymore */
6864 if (!actconn && listeners == 0)
6865 break;
6866
willy tarreau0f7af912005-12-17 12:21:26 +01006867#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01006868 {
6869 int time2;
6870 time2 = stats();
6871 next_time = MINTIME(time2, next_time);
6872 }
willy tarreau0f7af912005-12-17 12:21:26 +01006873#endif
6874
willy tarreau1c2ad212005-12-18 01:11:29 +01006875 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6876
6877 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
6878 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
6879
6880 if ((ro^rn) | (wo^wn)) {
6881 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6882#define FDSETS_ARE_INT_ALIGNED
6883#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01006884
willy tarreauad90a0c2005-12-18 01:09:15 +01006885#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6886#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01006887 pr = (ro >> count) & 1;
6888 pw = (wo >> count) & 1;
6889 sr = (rn >> count) & 1;
6890 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01006891#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006892 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
6893 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
6894 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6895 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01006896#endif
6897#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006898 pr = FD_ISSET(fd, PrevReadEvent);
6899 pw = FD_ISSET(fd, PrevWriteEvent);
6900 sr = FD_ISSET(fd, StaticReadEvent);
6901 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01006902#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01006903 if (!((sr^pr) | (sw^pw)))
6904 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01006905
willy tarreau1c2ad212005-12-18 01:11:29 +01006906 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
6907 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01006908
willy tarreaub952e1d2005-12-18 01:31:20 +01006909#ifdef EPOLL_CTL_MOD_WORKAROUND
6910 /* I encountered a rarely reproducible problem with
6911 * EPOLL_CTL_MOD where a modified FD (systematically
6912 * the one in epoll_events[0], fd#7) would sometimes
6913 * be set EPOLL_OUT while asked for a read ! This is
6914 * with the 2.4 epoll patch. The workaround is to
6915 * delete then recreate in case of modification.
6916 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
6917 * nor RHEL kernels.
6918 */
6919
6920 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
6921 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
6922
6923 if ((sr | sw))
6924 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
6925#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006926 if ((pr | pw)) {
6927 /* the file-descriptor already exists... */
6928 if ((sr | sw)) {
6929 /* ...and it will still exist */
6930 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
6931 // perror("epoll_ctl(MOD)");
6932 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006933 }
6934 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01006935 /* ...and it will be removed */
6936 if (fdtab[fd].state != FD_STCLOSE &&
6937 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
6938 // perror("epoll_ctl(DEL)");
6939 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006940 }
6941 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006942 } else {
6943 /* the file-descriptor did not exist, let's add it */
6944 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
6945 // perror("epoll_ctl(ADD)");
6946 // exit(1);
6947 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006948 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006949#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01006950 }
6951 ((int*)PrevReadEvent)[fds] = rn;
6952 ((int*)PrevWriteEvent)[fds] = wn;
6953 }
6954 }
6955
6956 /* now let's wait for events */
6957 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
6958 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006959
willy tarreau1c2ad212005-12-18 01:11:29 +01006960 for (count = 0; count < status; count++) {
6961 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01006962
6963 if (FD_ISSET(fd, StaticReadEvent)) {
6964 if (fdtab[fd].state == FD_STCLOSE)
6965 continue;
6966 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
6967 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006968 }
willy tarreau05be12b2006-03-19 19:35:00 +01006969
6970 if (FD_ISSET(fd, StaticWriteEvent)) {
6971 if (fdtab[fd].state == FD_STCLOSE)
6972 continue;
6973 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
6974 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006975 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006976 }
6977 }
6978 return 1;
6979}
6980#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006981
willy tarreauad90a0c2005-12-18 01:09:15 +01006982
willy tarreau5cbea6f2005-12-17 12:48:26 +01006983
willy tarreau1c2ad212005-12-18 01:11:29 +01006984#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01006985
willy tarreau1c2ad212005-12-18 01:11:29 +01006986/*
6987 * Main poll() loop.
6988 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006989
willy tarreau1c2ad212005-12-18 01:11:29 +01006990/* does 3 actions :
6991 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6992 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6993 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6994 *
6995 * returns 0 if initialization failed, !0 otherwise.
6996 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006997
willy tarreau1c2ad212005-12-18 01:11:29 +01006998int poll_loop(int action) {
6999 int next_time;
7000 int status;
7001 int fd, nbfd;
7002
7003 int fds, count;
7004 int sr, sw;
7005 unsigned rn, wn; /* read new, write new */
7006
7007 /* private data */
7008 static struct pollfd *poll_events = NULL;
7009
7010 if (action == POLL_LOOP_ACTION_INIT) {
7011 poll_events = (struct pollfd*)
7012 calloc(1, sizeof(struct pollfd) * global.maxsock);
7013 return 1;
7014 }
7015 else if (action == POLL_LOOP_ACTION_CLEAN) {
7016 if (poll_events)
7017 free(poll_events);
7018 return 1;
7019 }
7020
7021 /* OK, it's POLL_LOOP_ACTION_RUN */
7022
7023 tv_now(&now);
7024
7025 while (1) {
7026 next_time = process_runnable_tasks();
7027
7028 /* stop when there's no connection left and we don't allow them anymore */
7029 if (!actconn && listeners == 0)
7030 break;
7031
7032#if STATTIME > 0
7033 {
7034 int time2;
7035 time2 = stats();
7036 next_time = MINTIME(time2, next_time);
7037 }
7038#endif
7039
7040
7041 nbfd = 0;
7042 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
7043
7044 rn = ((int*)StaticReadEvent)[fds];
7045 wn = ((int*)StaticWriteEvent)[fds];
7046
7047 if ((rn|wn)) {
7048 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
7049#define FDSETS_ARE_INT_ALIGNED
7050#ifdef FDSETS_ARE_INT_ALIGNED
7051
7052#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
7053#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
7054 sr = (rn >> count) & 1;
7055 sw = (wn >> count) & 1;
7056#else
7057 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
7058 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
7059#endif
7060#else
7061 sr = FD_ISSET(fd, StaticReadEvent);
7062 sw = FD_ISSET(fd, StaticWriteEvent);
7063#endif
7064 if ((sr|sw)) {
7065 poll_events[nbfd].fd = fd;
7066 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
7067 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01007068 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007069 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007070 }
7071 }
7072
7073 /* now let's wait for events */
7074 status = poll(poll_events, nbfd, next_time);
7075 tv_now(&now);
7076
7077 for (count = 0; status > 0 && count < nbfd; count++) {
7078 fd = poll_events[count].fd;
7079
7080 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
7081 continue;
7082
7083 /* ok, we found one active fd */
7084 status--;
7085
willy tarreau05be12b2006-03-19 19:35:00 +01007086 if (FD_ISSET(fd, StaticReadEvent)) {
7087 if (fdtab[fd].state == FD_STCLOSE)
7088 continue;
7089 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
7090 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007091 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007092
willy tarreau05be12b2006-03-19 19:35:00 +01007093 if (FD_ISSET(fd, StaticWriteEvent)) {
7094 if (fdtab[fd].state == FD_STCLOSE)
7095 continue;
7096 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
7097 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007098 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007099 }
7100 }
7101 return 1;
7102}
willy tarreauad90a0c2005-12-18 01:09:15 +01007103#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01007104
willy tarreauad90a0c2005-12-18 01:09:15 +01007105
willy tarreauad90a0c2005-12-18 01:09:15 +01007106
willy tarreau1c2ad212005-12-18 01:11:29 +01007107/*
7108 * Main select() loop.
7109 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007110
willy tarreau1c2ad212005-12-18 01:11:29 +01007111/* does 3 actions :
7112 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
7113 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
7114 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
7115 *
7116 * returns 0 if initialization failed, !0 otherwise.
7117 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007118
willy tarreauad90a0c2005-12-18 01:09:15 +01007119
willy tarreau1c2ad212005-12-18 01:11:29 +01007120int select_loop(int action) {
7121 int next_time;
7122 int status;
7123 int fd,i;
7124 struct timeval delta;
7125 int readnotnull, writenotnull;
7126 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01007127
willy tarreau1c2ad212005-12-18 01:11:29 +01007128 if (action == POLL_LOOP_ACTION_INIT) {
7129 ReadEvent = (fd_set *)
7130 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
7131 WriteEvent = (fd_set *)
7132 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
7133 return 1;
7134 }
7135 else if (action == POLL_LOOP_ACTION_CLEAN) {
7136 if (WriteEvent) free(WriteEvent);
7137 if (ReadEvent) free(ReadEvent);
7138 return 1;
7139 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007140
willy tarreau1c2ad212005-12-18 01:11:29 +01007141 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01007142
willy tarreau1c2ad212005-12-18 01:11:29 +01007143 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01007144
willy tarreau1c2ad212005-12-18 01:11:29 +01007145 while (1) {
7146 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01007147
willy tarreau1c2ad212005-12-18 01:11:29 +01007148 /* stop when there's no connection left and we don't allow them anymore */
7149 if (!actconn && listeners == 0)
7150 break;
7151
7152#if STATTIME > 0
7153 {
7154 int time2;
7155 time2 = stats();
7156 next_time = MINTIME(time2, next_time);
7157 }
7158#endif
7159
willy tarreau1c2ad212005-12-18 01:11:29 +01007160 if (next_time > 0) { /* FIXME */
7161 /* Convert to timeval */
7162 /* to avoid eventual select loops due to timer precision */
7163 next_time += SCHEDULER_RESOLUTION;
7164 delta.tv_sec = next_time / 1000;
7165 delta.tv_usec = (next_time % 1000) * 1000;
7166 }
7167 else if (next_time == 0) { /* allow select to return immediately when needed */
7168 delta.tv_sec = delta.tv_usec = 0;
7169 }
7170
7171
7172 /* let's restore fdset state */
7173
7174 readnotnull = 0; writenotnull = 0;
7175 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
7176 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
7177 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
7178 }
7179
7180 // /* just a verification code, needs to be removed for performance */
7181 // for (i=0; i<maxfd; i++) {
7182 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
7183 // abort();
7184 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
7185 // abort();
7186 //
7187 // }
7188
7189 status = select(maxfd,
7190 readnotnull ? ReadEvent : NULL,
7191 writenotnull ? WriteEvent : NULL,
7192 NULL,
7193 (next_time >= 0) ? &delta : NULL);
7194
7195 /* this is an experiment on the separation of the select work */
7196 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
7197 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
7198
7199 tv_now(&now);
7200
7201 if (status > 0) { /* must proceed with events */
7202
7203 int fds;
7204 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01007205
willy tarreau1c2ad212005-12-18 01:11:29 +01007206 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
7207 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
7208 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
7209
7210 /* if we specify read first, the accepts and zero reads will be
7211 * seen first. Moreover, system buffers will be flushed faster.
7212 */
willy tarreau05be12b2006-03-19 19:35:00 +01007213 if (FD_ISSET(fd, ReadEvent)) {
7214 if (fdtab[fd].state == FD_STCLOSE)
7215 continue;
7216 fdtab[fd].read(fd);
7217 }
willy tarreau64a3cc32005-12-18 01:13:11 +01007218
willy tarreau05be12b2006-03-19 19:35:00 +01007219 if (FD_ISSET(fd, WriteEvent)) {
7220 if (fdtab[fd].state == FD_STCLOSE)
7221 continue;
7222 fdtab[fd].write(fd);
7223 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007224 }
7225 }
7226 else {
7227 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01007228 }
willy tarreau0f7af912005-12-17 12:21:26 +01007229 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007230 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01007231}
7232
7233
7234#if STATTIME > 0
7235/*
7236 * Display proxy statistics regularly. It is designed to be called from the
7237 * select_loop().
7238 */
7239int stats(void) {
7240 static int lines;
7241 static struct timeval nextevt;
7242 static struct timeval lastevt;
7243 static struct timeval starttime = {0,0};
7244 unsigned long totaltime, deltatime;
7245 int ret;
7246
willy tarreau750a4722005-12-17 13:21:24 +01007247 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01007248 deltatime = (tv_diff(&lastevt, &now)?:1);
7249 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01007250
willy tarreau9fe663a2005-12-17 13:02:59 +01007251 if (global.mode & MODE_STATS) {
7252 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007253 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007254 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
7255 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007256 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01007257 actconn, totalconn,
7258 stats_tsk_new, stats_tsk_good,
7259 stats_tsk_left, stats_tsk_right,
7260 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
7261 }
7262 }
7263
7264 tv_delayfrom(&nextevt, &now, STATTIME);
7265
7266 lastevt=now;
7267 }
7268 ret = tv_remain(&now, &nextevt);
7269 return ret;
7270}
7271#endif
7272
7273
7274/*
7275 * this function enables proxies when there are enough free sessions,
7276 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01007277 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01007278 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01007279 */
7280static int maintain_proxies(void) {
7281 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01007282 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007283 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01007284
7285 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01007286 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01007287
7288 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01007289 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01007290 while (p) {
7291 if (p->nbconn < p->maxconn) {
7292 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007293 for (l = p->listen; l != NULL; l = l->next) {
7294 FD_SET(l->fd, StaticReadEvent);
7295 }
willy tarreau0f7af912005-12-17 12:21:26 +01007296 p->state = PR_STRUN;
7297 }
7298 }
7299 else {
7300 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007301 for (l = p->listen; l != NULL; l = l->next) {
7302 FD_CLR(l->fd, StaticReadEvent);
7303 }
willy tarreau0f7af912005-12-17 12:21:26 +01007304 p->state = PR_STIDLE;
7305 }
7306 }
7307 p = p->next;
7308 }
7309 }
7310 else { /* block all proxies */
7311 while (p) {
7312 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007313 for (l = p->listen; l != NULL; l = l->next) {
7314 FD_CLR(l->fd, StaticReadEvent);
7315 }
willy tarreau0f7af912005-12-17 12:21:26 +01007316 p->state = PR_STIDLE;
7317 }
7318 p = p->next;
7319 }
7320 }
7321
willy tarreau5cbea6f2005-12-17 12:48:26 +01007322 if (stopping) {
7323 p = proxy;
7324 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007325 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007326 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01007327 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007328 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01007329 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01007330 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01007331
willy tarreaua41a8b42005-12-17 14:02:24 +01007332 for (l = p->listen; l != NULL; l = l->next) {
7333 fd_delete(l->fd);
7334 listeners--;
7335 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007336 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007337 }
7338 else {
7339 tleft = MINTIME(t, tleft);
7340 }
7341 }
7342 p = p->next;
7343 }
7344 }
7345 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01007346}
7347
7348/*
7349 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01007350 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
7351 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01007352 */
7353static void soft_stop(void) {
7354 struct proxy *p;
7355
7356 stopping = 1;
7357 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007358 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01007359 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01007360 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01007361 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01007362 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01007363 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01007364 }
willy tarreau0f7af912005-12-17 12:21:26 +01007365 p = p->next;
7366 }
7367}
7368
willy tarreaufac1a862006-05-21 10:20:28 +02007369/*
7370 * Linux unbinds the listen socket after a SHUT_RD, and ignores SHUT_WR.
7371 * Solaris refuses either shutdown().
7372 * OpenBSD ignores SHUT_RD but closes upon SHUT_WR and refuses to rebind.
7373 * So a common validation path involves SHUT_WR && listen && SHUT_RD.
7374 * If disabling at least one listener returns an error, then the proxy
7375 * state is set to PR_STERROR because we don't know how to resume from this.
7376 */
willy tarreaudbd3bef2006-01-20 19:35:18 +01007377static void pause_proxy(struct proxy *p) {
7378 struct listener *l;
7379 for (l = p->listen; l != NULL; l = l->next) {
willy tarreaufac1a862006-05-21 10:20:28 +02007380 if (shutdown(l->fd, SHUT_WR) == 0 && listen(l->fd, p->maxconn) == 0 &&
7381 shutdown(l->fd, SHUT_RD) == 0) {
Willy TARREAU007aa462006-05-14 09:55:23 +02007382 FD_CLR(l->fd, StaticReadEvent);
willy tarreaufac1a862006-05-21 10:20:28 +02007383 if (p->state != PR_STERROR)
7384 p->state = PR_STPAUSED;
Willy TARREAU007aa462006-05-14 09:55:23 +02007385 }
willy tarreaufac1a862006-05-21 10:20:28 +02007386 else
7387 p->state = PR_STERROR;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007388 }
7389}
7390
7391/*
7392 * This function temporarily disables listening so that another new instance
7393 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01007394 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01007395 * the proxy, or a SIGTTIN can be sent to listen again.
7396 */
7397static void pause_proxies(void) {
Willy TARREAU007aa462006-05-14 09:55:23 +02007398 int err;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007399 struct proxy *p;
7400
Willy TARREAU007aa462006-05-14 09:55:23 +02007401 err = 0;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007402 p = proxy;
7403 tv_now(&now); /* else, the old time before select will be used */
7404 while (p) {
willy tarreaufac1a862006-05-21 10:20:28 +02007405 if (p->state != PR_STERROR && p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007406 Warning("Pausing proxy %s.\n", p->id);
7407 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
7408 pause_proxy(p);
Willy TARREAU007aa462006-05-14 09:55:23 +02007409 if (p->state != PR_STPAUSED) {
7410 err |= 1;
7411 Warning("Proxy %s failed to enter pause mode.\n", p->id);
7412 send_log(p, LOG_WARNING, "Proxy %s failed to enter pause mode.\n", p->id);
7413 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007414 }
7415 p = p->next;
7416 }
Willy TARREAU007aa462006-05-14 09:55:23 +02007417 if (err) {
7418 Warning("Some proxies refused to pause, performing soft stop now.\n");
7419 send_log(p, LOG_WARNING, "Some proxies refused to pause, performing soft stop now.\n");
7420 soft_stop();
7421 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007422}
7423
7424
7425/*
7426 * This function reactivates listening. This can be used after a call to
7427 * sig_pause(), for example when a new instance has failed starting up.
7428 * It is designed to be called upon reception of a SIGTTIN.
7429 */
7430static void listen_proxies(void) {
7431 struct proxy *p;
7432 struct listener *l;
7433
7434 p = proxy;
7435 tv_now(&now); /* else, the old time before select will be used */
7436 while (p) {
7437 if (p->state == PR_STPAUSED) {
7438 Warning("Enabling proxy %s.\n", p->id);
7439 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
7440
7441 for (l = p->listen; l != NULL; l = l->next) {
7442 if (listen(l->fd, p->maxconn) == 0) {
7443 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
7444 FD_SET(l->fd, StaticReadEvent);
7445 p->state = PR_STRUN;
7446 }
7447 else
7448 p->state = PR_STIDLE;
7449 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01007450 int port;
7451
7452 if (l->addr.ss_family == AF_INET6)
7453 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
7454 else
7455 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
7456
willy tarreaudbd3bef2006-01-20 19:35:18 +01007457 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01007458 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01007459 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01007460 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01007461 /* Another port might have been enabled. Let's stop everything. */
7462 pause_proxy(p);
7463 break;
7464 }
7465 }
7466 }
7467 p = p->next;
7468 }
7469}
7470
7471
willy tarreau0f7af912005-12-17 12:21:26 +01007472/*
7473 * upon SIGUSR1, let's have a soft stop.
7474 */
7475void sig_soft_stop(int sig) {
7476 soft_stop();
7477 signal(sig, SIG_IGN);
7478}
7479
willy tarreaudbd3bef2006-01-20 19:35:18 +01007480/*
7481 * upon SIGTTOU, we pause everything
7482 */
7483void sig_pause(int sig) {
7484 pause_proxies();
7485 signal(sig, sig_pause);
7486}
willy tarreau0f7af912005-12-17 12:21:26 +01007487
willy tarreau8337c6b2005-12-17 13:41:01 +01007488/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01007489 * upon SIGTTIN, let's have a soft stop.
7490 */
7491void sig_listen(int sig) {
7492 listen_proxies();
7493 signal(sig, sig_listen);
7494}
7495
7496/*
willy tarreau8337c6b2005-12-17 13:41:01 +01007497 * this function dumps every server's state when the process receives SIGHUP.
7498 */
7499void sig_dump_state(int sig) {
7500 struct proxy *p = proxy;
7501
7502 Warning("SIGHUP received, dumping servers states.\n");
7503 while (p) {
7504 struct server *s = p->srv;
7505
willy tarreau4632c212006-05-02 23:32:51 +02007506 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01007507 while (s) {
willy tarreau4632c212006-05-02 23:32:51 +02007508 snprintf(trash, sizeof(trash),
7509 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %d tot.",
7510 p->id, s->id,
7511 (s->state & SRV_RUNNING) ? "UP" : "DOWN",
7512 s->cur_sess, s->nbpend, s->cum_sess);
willy tarreau14b4d432006-04-07 18:23:29 +02007513 Warning("%s\n", trash);
7514 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01007515 s = s->next;
7516 }
willy tarreaudd07e972005-12-18 00:48:48 +01007517
willy tarreau62084d42006-03-24 18:57:41 +01007518 if (p->srv_act == 0) {
willy tarreau4632c212006-05-02 23:32:51 +02007519 snprintf(trash, sizeof(trash),
7520 "SIGHUP: Proxy %s %s ! Conn: %d act, %d pend (%d unass), %d tot.",
7521 p->id,
7522 (p->srv_bck) ? "is running on backup servers" : "has no server available",
7523 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02007524 } else {
7525 snprintf(trash, sizeof(trash),
willy tarreau4632c212006-05-02 23:32:51 +02007526 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
7527 " Conn: %d act, %d pend (%d unass), %d tot.",
7528 p->id, p->srv_act, p->srv_bck,
7529 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02007530 }
7531 Warning("%s\n", trash);
7532 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01007533
willy tarreau8337c6b2005-12-17 13:41:01 +01007534 p = p->next;
7535 }
7536 signal(sig, sig_dump_state);
7537}
7538
willy tarreau0f7af912005-12-17 12:21:26 +01007539void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007540 struct task *t, *tnext;
7541 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01007542
willy tarreau5e698ef2006-05-02 14:51:00 +02007543 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
7544 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007545 tnext = t->next;
7546 s = t->context;
7547 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
7548 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
7549 "req=%d, rep=%d, clifd=%d\n",
7550 s, tv_remain(&now, &t->expire),
7551 s->cli_state,
7552 s->srv_state,
7553 FD_ISSET(s->cli_fd, StaticReadEvent),
7554 FD_ISSET(s->cli_fd, StaticWriteEvent),
7555 FD_ISSET(s->srv_fd, StaticReadEvent),
7556 FD_ISSET(s->srv_fd, StaticWriteEvent),
7557 s->req->l, s->rep?s->rep->l:0, s->cli_fd
7558 );
willy tarreau0f7af912005-12-17 12:21:26 +01007559 }
willy tarreau12350152005-12-18 01:03:27 +01007560}
7561
willy tarreau64a3cc32005-12-18 01:13:11 +01007562#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01007563static void fast_stop(void)
7564{
7565 struct proxy *p;
7566 p = proxy;
7567 while (p) {
7568 p->grace = 0;
7569 p = p->next;
7570 }
7571 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01007572}
7573
willy tarreau12350152005-12-18 01:03:27 +01007574void sig_int(int sig) {
7575 /* This would normally be a hard stop,
7576 but we want to be sure about deallocation,
7577 and so on, so we do a soft stop with
7578 0 GRACE time
7579 */
7580 fast_stop();
7581 /* If we are killed twice, we decide to die*/
7582 signal(sig, SIG_DFL);
7583}
7584
7585void sig_term(int sig) {
7586 /* This would normally be a hard stop,
7587 but we want to be sure about deallocation,
7588 and so on, so we do a soft stop with
7589 0 GRACE time
7590 */
7591 fast_stop();
7592 /* If we are killed twice, we decide to die*/
7593 signal(sig, SIG_DFL);
7594}
willy tarreau64a3cc32005-12-18 01:13:11 +01007595#endif
willy tarreau12350152005-12-18 01:03:27 +01007596
willy tarreauc1f47532005-12-18 01:08:26 +01007597/* returns the pointer to an error in the replacement string, or NULL if OK */
7598char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01007599 struct hdr_exp *exp;
7600
willy tarreauc1f47532005-12-18 01:08:26 +01007601 if (replace != NULL) {
7602 char *err;
7603 err = check_replace_string(replace);
7604 if (err)
7605 return err;
7606 }
7607
willy tarreaue39cd132005-12-17 13:00:18 +01007608 while (*head != NULL)
7609 head = &(*head)->next;
7610
7611 exp = calloc(1, sizeof(struct hdr_exp));
7612
7613 exp->preg = preg;
7614 exp->replace = replace;
7615 exp->action = action;
7616 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01007617
7618 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007619}
7620
willy tarreau9fe663a2005-12-17 13:02:59 +01007621
willy tarreau0f7af912005-12-17 12:21:26 +01007622/*
willy tarreau9fe663a2005-12-17 13:02:59 +01007623 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01007624 */
willy tarreau9fe663a2005-12-17 13:02:59 +01007625int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01007626
willy tarreau9fe663a2005-12-17 13:02:59 +01007627 if (!strcmp(args[0], "global")) { /* new section */
7628 /* no option, nothing special to do */
7629 return 0;
7630 }
7631 else if (!strcmp(args[0], "daemon")) {
7632 global.mode |= MODE_DAEMON;
7633 }
7634 else if (!strcmp(args[0], "debug")) {
7635 global.mode |= MODE_DEBUG;
7636 }
willy tarreau64a3cc32005-12-18 01:13:11 +01007637 else if (!strcmp(args[0], "noepoll")) {
7638 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
7639 }
7640 else if (!strcmp(args[0], "nopoll")) {
7641 cfg_polling_mechanism &= ~POLL_USE_POLL;
7642 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007643 else if (!strcmp(args[0], "quiet")) {
7644 global.mode |= MODE_QUIET;
7645 }
7646 else if (!strcmp(args[0], "stats")) {
7647 global.mode |= MODE_STATS;
7648 }
7649 else if (!strcmp(args[0], "uid")) {
7650 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007651 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007652 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007653 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007654 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007655 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007656 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007657 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007658 global.uid = atol(args[1]);
7659 }
7660 else if (!strcmp(args[0], "gid")) {
7661 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007662 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007663 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007664 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007665 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007666 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007667 return -1;
7668 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007669 global.gid = atol(args[1]);
7670 }
7671 else if (!strcmp(args[0], "nbproc")) {
7672 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007673 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007674 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007675 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007676 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007677 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007678 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007679 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007680 global.nbproc = atol(args[1]);
7681 }
7682 else if (!strcmp(args[0], "maxconn")) {
7683 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007684 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007685 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007686 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007687 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007688 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007689 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007690 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007691 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01007692#ifdef SYSTEM_MAXCONN
7693 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
7694 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);
7695 global.maxconn = DEFAULT_MAXCONN;
7696 }
7697#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01007698 }
willy tarreaub1285d52005-12-18 01:20:14 +01007699 else if (!strcmp(args[0], "ulimit-n")) {
7700 if (global.rlimit_nofile != 0) {
7701 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7702 return 0;
7703 }
7704 if (*(args[1]) == 0) {
7705 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
7706 return -1;
7707 }
7708 global.rlimit_nofile = atol(args[1]);
7709 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007710 else if (!strcmp(args[0], "chroot")) {
7711 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007712 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007713 return 0;
7714 }
7715 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007716 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007717 return -1;
7718 }
7719 global.chroot = strdup(args[1]);
7720 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007721 else if (!strcmp(args[0], "pidfile")) {
7722 if (global.pidfile != NULL) {
7723 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7724 return 0;
7725 }
7726 if (*(args[1]) == 0) {
7727 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
7728 return -1;
7729 }
7730 global.pidfile = strdup(args[1]);
7731 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007732 else if (!strcmp(args[0], "log")) { /* syslog server address */
7733 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01007734 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007735
7736 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007737 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007738 return -1;
7739 }
7740
7741 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7742 if (!strcmp(log_facilities[facility], args[2]))
7743 break;
7744
7745 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007746 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007747 exit(1);
7748 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007749
7750 level = 7; /* max syslog level = debug */
7751 if (*(args[3])) {
7752 while (level >= 0 && strcmp(log_levels[level], args[3]))
7753 level--;
7754 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007755 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007756 exit(1);
7757 }
7758 }
7759
willy tarreau9fe663a2005-12-17 13:02:59 +01007760 sa = str2sa(args[1]);
7761 if (!sa->sin_port)
7762 sa->sin_port = htons(SYSLOG_PORT);
7763
7764 if (global.logfac1 == -1) {
7765 global.logsrv1 = *sa;
7766 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007767 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007768 }
7769 else if (global.logfac2 == -1) {
7770 global.logsrv2 = *sa;
7771 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007772 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007773 }
7774 else {
7775 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
7776 return -1;
7777 }
7778
7779 }
7780 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007781 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01007782 return -1;
7783 }
7784 return 0;
7785}
7786
7787
willy tarreaua41a8b42005-12-17 14:02:24 +01007788void init_default_instance() {
7789 memset(&defproxy, 0, sizeof(defproxy));
7790 defproxy.mode = PR_MODE_TCP;
7791 defproxy.state = PR_STNEW;
7792 defproxy.maxconn = cfg_maxpconn;
7793 defproxy.conn_retries = CONN_RETRIES;
7794 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
7795}
7796
willy tarreau9fe663a2005-12-17 13:02:59 +01007797/*
7798 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
7799 */
7800int cfg_parse_listen(char *file, int linenum, char **args) {
7801 static struct proxy *curproxy = NULL;
7802 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01007803 char *err;
willy tarreau12350152005-12-18 01:03:27 +01007804 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01007805
7806 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01007807 if (!*args[1]) {
7808 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
7809 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007810 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007811 return -1;
7812 }
7813
7814 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007815 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007816 return -1;
7817 }
willy tarreaudfece232006-05-02 00:19:57 +02007818
willy tarreau9fe663a2005-12-17 13:02:59 +01007819 curproxy->next = proxy;
7820 proxy = curproxy;
willy tarreaudfece232006-05-02 00:19:57 +02007821 LIST_INIT(&curproxy->pendconns);
7822
willy tarreau9fe663a2005-12-17 13:02:59 +01007823 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01007824
7825 /* parse the listener address if any */
7826 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007827 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007828 if (!curproxy->listen)
7829 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007830 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01007831 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007832
willy tarreau9fe663a2005-12-17 13:02:59 +01007833 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01007834 curproxy->state = defproxy.state;
7835 curproxy->maxconn = defproxy.maxconn;
7836 curproxy->conn_retries = defproxy.conn_retries;
7837 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007838
7839 if (defproxy.check_req)
7840 curproxy->check_req = strdup(defproxy.check_req);
7841 curproxy->check_len = defproxy.check_len;
7842
7843 if (defproxy.cookie_name)
7844 curproxy->cookie_name = strdup(defproxy.cookie_name);
7845 curproxy->cookie_len = defproxy.cookie_len;
7846
7847 if (defproxy.capture_name)
7848 curproxy->capture_name = strdup(defproxy.capture_name);
7849 curproxy->capture_namelen = defproxy.capture_namelen;
7850 curproxy->capture_len = defproxy.capture_len;
7851
7852 if (defproxy.errmsg.msg400)
7853 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
7854 curproxy->errmsg.len400 = defproxy.errmsg.len400;
7855
7856 if (defproxy.errmsg.msg403)
7857 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
7858 curproxy->errmsg.len403 = defproxy.errmsg.len403;
7859
7860 if (defproxy.errmsg.msg408)
7861 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
7862 curproxy->errmsg.len408 = defproxy.errmsg.len408;
7863
7864 if (defproxy.errmsg.msg500)
7865 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
7866 curproxy->errmsg.len500 = defproxy.errmsg.len500;
7867
7868 if (defproxy.errmsg.msg502)
7869 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
7870 curproxy->errmsg.len502 = defproxy.errmsg.len502;
7871
7872 if (defproxy.errmsg.msg503)
7873 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
7874 curproxy->errmsg.len503 = defproxy.errmsg.len503;
7875
7876 if (defproxy.errmsg.msg504)
7877 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
7878 curproxy->errmsg.len504 = defproxy.errmsg.len504;
7879
willy tarreaua41a8b42005-12-17 14:02:24 +01007880 curproxy->clitimeout = defproxy.clitimeout;
7881 curproxy->contimeout = defproxy.contimeout;
7882 curproxy->srvtimeout = defproxy.srvtimeout;
7883 curproxy->mode = defproxy.mode;
7884 curproxy->logfac1 = defproxy.logfac1;
7885 curproxy->logsrv1 = defproxy.logsrv1;
7886 curproxy->loglev1 = defproxy.loglev1;
7887 curproxy->logfac2 = defproxy.logfac2;
7888 curproxy->logsrv2 = defproxy.logsrv2;
7889 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01007890 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01007891 curproxy->grace = defproxy.grace;
willy tarreau1f431b52006-05-21 14:46:15 +02007892 curproxy->uri_auth = defproxy.uri_auth;
willy tarreaua41a8b42005-12-17 14:02:24 +01007893 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01007894 curproxy->mon_net = defproxy.mon_net;
7895 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01007896 return 0;
7897 }
7898 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007899 /* some variables may have already been initialized earlier */
7900 if (defproxy.check_req) free(defproxy.check_req);
7901 if (defproxy.cookie_name) free(defproxy.cookie_name);
7902 if (defproxy.capture_name) free(defproxy.capture_name);
7903 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
7904 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
7905 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
7906 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
7907 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
7908 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
7909 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
willy tarreau1f431b52006-05-21 14:46:15 +02007910 /* we cannot free uri_auth because it might already be used */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007911 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01007912 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01007913 return 0;
7914 }
7915 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007916 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007917 return -1;
7918 }
7919
willy tarreaua41a8b42005-12-17 14:02:24 +01007920 if (!strcmp(args[0], "bind")) { /* new listen addresses */
7921 if (curproxy == &defproxy) {
7922 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7923 return -1;
7924 }
7925
7926 if (strchr(args[1], ':') == NULL) {
7927 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
7928 file, linenum, args[0]);
7929 return -1;
7930 }
7931 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007932 if (!curproxy->listen)
7933 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007934 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007935 return 0;
7936 }
willy tarreaub1285d52005-12-18 01:20:14 +01007937 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
7938 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
7939 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
7940 file, linenum, args[0]);
7941 return -1;
7942 }
7943 /* flush useless bits */
7944 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
7945 return 0;
7946 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007947 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01007948 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
7949 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
7950 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
7951 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007952 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007953 return -1;
7954 }
7955 }
7956 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01007957 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007958 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007959 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
7960 curproxy->state = PR_STNEW;
7961 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007962 else if (!strcmp(args[0], "cookie")) { /* cookie name */
7963 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007964// if (curproxy == &defproxy) {
7965// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7966// return -1;
7967// }
willy tarreaua41a8b42005-12-17 14:02:24 +01007968
willy tarreau9fe663a2005-12-17 13:02:59 +01007969 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007970// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7971// file, linenum);
7972// return 0;
7973 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007974 }
7975
7976 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007977 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
7978 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007979 return -1;
7980 }
7981 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007982 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007983
7984 cur_arg = 2;
7985 while (*(args[cur_arg])) {
7986 if (!strcmp(args[cur_arg], "rewrite")) {
7987 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01007988 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007989 else if (!strcmp(args[cur_arg], "indirect")) {
7990 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01007991 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007992 else if (!strcmp(args[cur_arg], "insert")) {
7993 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01007994 }
willy tarreau240afa62005-12-17 13:14:35 +01007995 else if (!strcmp(args[cur_arg], "nocache")) {
7996 curproxy->options |= PR_O_COOK_NOC;
7997 }
willy tarreaucd878942005-12-17 13:27:43 +01007998 else if (!strcmp(args[cur_arg], "postonly")) {
7999 curproxy->options |= PR_O_COOK_POST;
8000 }
willy tarreau0174f312005-12-18 01:02:42 +01008001 else if (!strcmp(args[cur_arg], "prefix")) {
8002 curproxy->options |= PR_O_COOK_PFX;
8003 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008004 else {
willy tarreau0174f312005-12-18 01:02:42 +01008005 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008006 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01008007 return -1;
8008 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008009 cur_arg++;
8010 }
willy tarreau0174f312005-12-18 01:02:42 +01008011 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
8012 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
8013 file, linenum);
8014 return -1;
8015 }
8016
8017 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
8018 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01008019 file, linenum);
8020 return -1;
8021 }
willy tarreau12350152005-12-18 01:03:27 +01008022 }/* end else if (!strcmp(args[0], "cookie")) */
8023 else if (!strcmp(args[0], "appsession")) { /* cookie name */
8024// if (curproxy == &defproxy) {
8025// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8026// return -1;
8027// }
8028
8029 if (curproxy->appsession_name != NULL) {
8030// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
8031// file, linenum);
8032// return 0;
8033 free(curproxy->appsession_name);
8034 }
8035
8036 if (*(args[5]) == 0) {
8037 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
8038 file, linenum, args[0]);
8039 return -1;
8040 }
8041 have_appsession = 1;
8042 curproxy->appsession_name = strdup(args[1]);
8043 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
8044 curproxy->appsession_len = atoi(args[3]);
8045 curproxy->appsession_timeout = atoi(args[5]);
8046 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
8047 if (rc) {
8048 Alert("Error Init Appsession Hashtable.\n");
8049 return -1;
8050 }
8051 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01008052 else if (!strcmp(args[0], "capture")) {
8053 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
8054 // if (curproxy == &defproxy) {
8055 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8056 // return -1;
8057 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01008058
willy tarreau4302f492005-12-18 01:00:37 +01008059 if (curproxy->capture_name != NULL) {
8060 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
8061 // file, linenum, args[0]);
8062 // return 0;
8063 free(curproxy->capture_name);
8064 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008065
willy tarreau4302f492005-12-18 01:00:37 +01008066 if (*(args[4]) == 0) {
8067 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
8068 file, linenum, args[0]);
8069 return -1;
8070 }
8071 curproxy->capture_name = strdup(args[2]);
8072 curproxy->capture_namelen = strlen(curproxy->capture_name);
8073 curproxy->capture_len = atol(args[4]);
8074 if (curproxy->capture_len >= CAPTURE_LEN) {
8075 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
8076 file, linenum, CAPTURE_LEN - 1);
8077 curproxy->capture_len = CAPTURE_LEN - 1;
8078 }
8079 curproxy->to_log |= LW_COOKIE;
8080 }
8081 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
8082 struct cap_hdr *hdr;
8083
8084 if (curproxy == &defproxy) {
8085 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
8086 return -1;
8087 }
8088
8089 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
8090 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
8091 file, linenum, args[0], args[1]);
8092 return -1;
8093 }
8094
8095 hdr = calloc(sizeof(struct cap_hdr), 1);
8096 hdr->next = curproxy->req_cap;
8097 hdr->name = strdup(args[3]);
8098 hdr->namelen = strlen(args[3]);
8099 hdr->len = atol(args[5]);
8100 hdr->index = curproxy->nb_req_cap++;
8101 curproxy->req_cap = hdr;
8102 curproxy->to_log |= LW_REQHDR;
8103 }
8104 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
8105 struct cap_hdr *hdr;
8106
8107 if (curproxy == &defproxy) {
8108 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
8109 return -1;
8110 }
8111
8112 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
8113 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
8114 file, linenum, args[0], args[1]);
8115 return -1;
8116 }
8117 hdr = calloc(sizeof(struct cap_hdr), 1);
8118 hdr->next = curproxy->rsp_cap;
8119 hdr->name = strdup(args[3]);
8120 hdr->namelen = strlen(args[3]);
8121 hdr->len = atol(args[5]);
8122 hdr->index = curproxy->nb_rsp_cap++;
8123 curproxy->rsp_cap = hdr;
8124 curproxy->to_log |= LW_RSPHDR;
8125 }
8126 else {
8127 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008128 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008129 return -1;
8130 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008131 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008132 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008133 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008134 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008135 return 0;
8136 }
8137 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008138 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8139 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008140 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008141 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008142 curproxy->contimeout = atol(args[1]);
8143 }
8144 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008145 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008146 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
8147 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008148 return 0;
8149 }
8150 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008151 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8152 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008153 return -1;
8154 }
8155 curproxy->clitimeout = atol(args[1]);
8156 }
8157 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008158 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008159 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008160 return 0;
8161 }
8162 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008163 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8164 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01008165 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008166 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008167 curproxy->srvtimeout = atol(args[1]);
8168 }
8169 else if (!strcmp(args[0], "retries")) { /* connection retries */
8170 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008171 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
8172 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008173 return -1;
8174 }
8175 curproxy->conn_retries = atol(args[1]);
8176 }
willy tarreau9e138862006-05-14 23:06:28 +02008177 else if (!strcmp(args[0], "stats")) {
willy tarreau1f431b52006-05-21 14:46:15 +02008178 if (curproxy != &defproxy && curproxy->uri_auth == defproxy.uri_auth)
8179 curproxy->uri_auth = NULL; /* we must detach from the default config */
8180
willy tarreau9e138862006-05-14 23:06:28 +02008181 if (*(args[1]) == 0) {
willy tarreau1f431b52006-05-21 14:46:15 +02008182 Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'auth', 'scope' or 'enable'.\n", file, linenum, args[0]);
willy tarreau9e138862006-05-14 23:06:28 +02008183 return -1;
8184 } else if (!strcmp(args[1], "uri")) {
8185 if (*(args[2]) == 0) {
8186 Alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
8187 return -1;
8188 } else if (!stats_set_uri(&curproxy->uri_auth, args[2])) {
8189 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8190 return -1;
8191 }
8192 } else if (!strcmp(args[1], "realm")) {
8193 if (*(args[2]) == 0) {
8194 Alert("parsing [%s:%d] : 'realm' needs an realm name.\n", file, linenum);
8195 return -1;
8196 } else if (!stats_set_realm(&curproxy->uri_auth, args[2])) {
8197 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8198 return -1;
8199 }
8200 } else if (!strcmp(args[1], "auth")) {
8201 if (*(args[2]) == 0) {
8202 Alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
8203 return -1;
8204 } else if (!stats_add_auth(&curproxy->uri_auth, args[2])) {
8205 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8206 return -1;
8207 }
willy tarreau1f431b52006-05-21 14:46:15 +02008208 } else if (!strcmp(args[1], "scope")) {
8209 if (*(args[2]) == 0) {
8210 Alert("parsing [%s:%d] : 'scope' needs a proxy name.\n", file, linenum);
8211 return -1;
8212 } else if (!stats_add_scope(&curproxy->uri_auth, args[2])) {
8213 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8214 return -1;
8215 }
willy tarreau9e138862006-05-14 23:06:28 +02008216 } else if (!strcmp(args[1], "enable")) {
8217 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
8218 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8219 return -1;
8220 }
8221 } else {
8222 Alert("parsing [%s:%d] : unknown stats parameter '%s' (expects 'uri', 'realm', 'auth' or 'enable').\n",
8223 file, linenum, args[0]);
8224 return -1;
8225 }
8226 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008227 else if (!strcmp(args[0], "option")) {
8228 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008229 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008230 return -1;
8231 }
8232 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01008233 /* enable reconnections to dispatch */
8234 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01008235#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01008236 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01008237 /* enable transparent proxy connections */
8238 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01008239#endif
8240 else if (!strcmp(args[1], "keepalive"))
8241 /* enable keep-alive */
8242 curproxy->options |= PR_O_KEEPALIVE;
8243 else if (!strcmp(args[1], "forwardfor"))
8244 /* insert x-forwarded-for field */
8245 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01008246 else if (!strcmp(args[1], "logasap"))
8247 /* log as soon as possible, without waiting for the session to complete */
8248 curproxy->options |= PR_O_LOGASAP;
8249 else if (!strcmp(args[1], "httpclose"))
8250 /* force connection: close in both directions in HTTP mode */
8251 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01008252 else if (!strcmp(args[1], "forceclose"))
8253 /* force connection: close in both directions in HTTP mode and enforce end of session */
8254 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01008255 else if (!strcmp(args[1], "checkcache"))
8256 /* require examination of cacheability of the 'set-cookie' field */
8257 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01008258 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01008259 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01008260 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01008261 else if (!strcmp(args[1], "tcplog"))
8262 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01008263 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01008264 else if (!strcmp(args[1], "dontlognull")) {
8265 /* don't log empty requests */
8266 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008267 }
willy tarreaub952e1d2005-12-18 01:31:20 +01008268 else if (!strcmp(args[1], "tcpka")) {
8269 /* enable TCP keep-alives on client and server sessions */
8270 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
8271 }
8272 else if (!strcmp(args[1], "clitcpka")) {
8273 /* enable TCP keep-alives on client sessions */
8274 curproxy->options |= PR_O_TCP_CLI_KA;
8275 }
8276 else if (!strcmp(args[1], "srvtcpka")) {
8277 /* enable TCP keep-alives on server sessions */
8278 curproxy->options |= PR_O_TCP_SRV_KA;
8279 }
Willy TARREAU3481c462006-03-01 22:37:57 +01008280 else if (!strcmp(args[1], "allbackups")) {
8281 /* Use all backup servers simultaneously */
8282 curproxy->options |= PR_O_USE_ALL_BK;
8283 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008284 else if (!strcmp(args[1], "httpchk")) {
8285 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008286 if (curproxy->check_req != NULL) {
8287 free(curproxy->check_req);
8288 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008289 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01008290 if (!*args[2]) { /* no argument */
8291 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
8292 curproxy->check_len = strlen(DEF_CHECK_REQ);
8293 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01008294 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
8295 curproxy->check_req = (char *)malloc(reqlen);
8296 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
8297 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008298 } else { /* more arguments : METHOD URI [HTTP_VER] */
8299 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
8300 if (*args[4])
8301 reqlen += strlen(args[4]);
8302 else
8303 reqlen += strlen("HTTP/1.0");
8304
8305 curproxy->check_req = (char *)malloc(reqlen);
8306 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
8307 "%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 +01008308 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008309 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008310 else if (!strcmp(args[1], "persist")) {
8311 /* persist on using the server specified by the cookie, even when it's down */
8312 curproxy->options |= PR_O_PERSIST;
8313 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008314 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008315 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008316 return -1;
8317 }
8318 return 0;
8319 }
8320 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
8321 /* enable reconnections to dispatch */
8322 curproxy->options |= PR_O_REDISP;
8323 }
willy tarreaua1598082005-12-17 13:08:06 +01008324#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01008325 else if (!strcmp(args[0], "transparent")) {
8326 /* enable transparent proxy connections */
8327 curproxy->options |= PR_O_TRANSP;
8328 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008329#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01008330 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
8331 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008332 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008333 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008334 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008335 curproxy->maxconn = atol(args[1]);
8336 }
8337 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
8338 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008339 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008340 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008341 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008342 curproxy->grace = atol(args[1]);
8343 }
8344 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01008345 if (curproxy == &defproxy) {
8346 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8347 return -1;
8348 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008349 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008350 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008351 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008352 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008353 curproxy->dispatch_addr = *str2sa(args[1]);
8354 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008355 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01008356 if (*(args[1])) {
8357 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008358 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01008359 }
willy tarreau1a3442d2006-03-24 21:03:20 +01008360 else if (!strcmp(args[1], "source")) {
8361 curproxy->options |= PR_O_BALANCE_SH;
8362 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008363 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01008364 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008365 return -1;
8366 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008367 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008368 else /* if no option is set, use round-robin by default */
8369 curproxy->options |= PR_O_BALANCE_RR;
8370 }
8371 else if (!strcmp(args[0], "server")) { /* server address */
8372 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008373 char *rport;
8374 char *raddr;
8375 short realport;
8376 int do_check;
8377
8378 if (curproxy == &defproxy) {
8379 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8380 return -1;
8381 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008382
willy tarreaua41a8b42005-12-17 14:02:24 +01008383 if (!*args[2]) {
8384 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008385 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008386 return -1;
8387 }
8388 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
8389 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8390 return -1;
8391 }
willy tarreau0174f312005-12-18 01:02:42 +01008392
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008393 /* the servers are linked backwards first */
8394 newsrv->next = curproxy->srv;
8395 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01008396 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008397
willy tarreau18a957c2006-04-12 19:26:23 +02008398 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01008399 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01008400 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01008401 newsrv->id = strdup(args[1]);
8402
8403 /* several ways to check the port component :
8404 * - IP => port=+0, relative
8405 * - IP: => port=+0, relative
8406 * - IP:N => port=N, absolute
8407 * - IP:+N => port=+N, relative
8408 * - IP:-N => port=-N, relative
8409 */
8410 raddr = strdup(args[2]);
8411 rport = strchr(raddr, ':');
8412 if (rport) {
8413 *rport++ = 0;
8414 realport = atol(rport);
8415 if (!isdigit((int)*rport))
8416 newsrv->state |= SRV_MAPPORTS;
8417 } else {
8418 realport = 0;
8419 newsrv->state |= SRV_MAPPORTS;
8420 }
8421
8422 newsrv->addr = *str2sa(raddr);
8423 newsrv->addr.sin_port = htons(realport);
8424 free(raddr);
8425
willy tarreau9fe663a2005-12-17 13:02:59 +01008426 newsrv->curfd = -1; /* no health-check in progress */
8427 newsrv->inter = DEF_CHKINTR;
8428 newsrv->rise = DEF_RISETIME;
8429 newsrv->fall = DEF_FALLTIME;
8430 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
8431 cur_arg = 3;
8432 while (*args[cur_arg]) {
8433 if (!strcmp(args[cur_arg], "cookie")) {
8434 newsrv->cookie = strdup(args[cur_arg + 1]);
8435 newsrv->cklen = strlen(args[cur_arg + 1]);
8436 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01008437 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008438 else if (!strcmp(args[cur_arg], "rise")) {
8439 newsrv->rise = atol(args[cur_arg + 1]);
8440 newsrv->health = newsrv->rise;
8441 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01008442 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008443 else if (!strcmp(args[cur_arg], "fall")) {
8444 newsrv->fall = atol(args[cur_arg + 1]);
8445 cur_arg += 2;
8446 }
8447 else if (!strcmp(args[cur_arg], "inter")) {
8448 newsrv->inter = atol(args[cur_arg + 1]);
8449 cur_arg += 2;
8450 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008451 else if (!strcmp(args[cur_arg], "port")) {
8452 newsrv->check_port = atol(args[cur_arg + 1]);
8453 cur_arg += 2;
8454 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008455 else if (!strcmp(args[cur_arg], "backup")) {
8456 newsrv->state |= SRV_BACKUP;
8457 cur_arg ++;
8458 }
willy tarreaue3f023f2006-04-08 21:52:24 +02008459 else if (!strcmp(args[cur_arg], "weight")) {
8460 int w;
8461 w = atol(args[cur_arg + 1]);
8462 if (w < 1 || w > 256) {
8463 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
8464 file, linenum, newsrv->id, w);
8465 return -1;
8466 }
8467 newsrv->uweight = w - 1;
8468 cur_arg += 2;
8469 }
willy tarreau18a957c2006-04-12 19:26:23 +02008470 else if (!strcmp(args[cur_arg], "maxconn")) {
8471 newsrv->maxconn = atol(args[cur_arg + 1]);
8472 cur_arg += 2;
8473 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008474 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01008475 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01008476 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008477 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008478 }
willy tarreau0174f312005-12-18 01:02:42 +01008479 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
8480 if (!*args[cur_arg + 1]) {
8481 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
8482 file, linenum, "source");
8483 return -1;
8484 }
8485 newsrv->state |= SRV_BIND_SRC;
8486 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
8487 cur_arg += 2;
8488 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008489 else {
willy tarreaue3f023f2006-04-08 21:52:24 +02008490 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port', 'source', and 'weight'.\n",
willy tarreaua41a8b42005-12-17 14:02:24 +01008491 file, linenum, newsrv->id);
8492 return -1;
8493 }
8494 }
8495
8496 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008497 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
8498 newsrv->check_port = realport; /* by default */
8499 if (!newsrv->check_port) {
8500 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 +01008501 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01008502 return -1;
8503 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008504 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01008505 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008506
willy tarreau62084d42006-03-24 18:57:41 +01008507 if (newsrv->state & SRV_BACKUP)
8508 curproxy->srv_bck++;
8509 else
8510 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01008511 }
8512 else if (!strcmp(args[0], "log")) { /* syslog server address */
8513 struct sockaddr_in *sa;
8514 int facility;
8515
8516 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
8517 curproxy->logfac1 = global.logfac1;
8518 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01008519 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008520 curproxy->logfac2 = global.logfac2;
8521 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01008522 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01008523 }
8524 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01008525 int level;
8526
willy tarreau0f7af912005-12-17 12:21:26 +01008527 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
8528 if (!strcmp(log_facilities[facility], args[2]))
8529 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01008530
willy tarreau0f7af912005-12-17 12:21:26 +01008531 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008532 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01008533 exit(1);
8534 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008535
willy tarreau8337c6b2005-12-17 13:41:01 +01008536 level = 7; /* max syslog level = debug */
8537 if (*(args[3])) {
8538 while (level >= 0 && strcmp(log_levels[level], args[3]))
8539 level--;
8540 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008541 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008542 exit(1);
8543 }
8544 }
8545
willy tarreau0f7af912005-12-17 12:21:26 +01008546 sa = str2sa(args[1]);
8547 if (!sa->sin_port)
8548 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01008549
willy tarreau0f7af912005-12-17 12:21:26 +01008550 if (curproxy->logfac1 == -1) {
8551 curproxy->logsrv1 = *sa;
8552 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01008553 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01008554 }
8555 else if (curproxy->logfac2 == -1) {
8556 curproxy->logsrv2 = *sa;
8557 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01008558 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01008559 }
8560 else {
8561 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01008562 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008563 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008564 }
8565 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008566 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01008567 file, linenum);
8568 return -1;
8569 }
8570 }
willy tarreaua1598082005-12-17 13:08:06 +01008571 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01008572 if (!*args[1]) {
8573 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008574 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01008575 return -1;
8576 }
8577
8578 curproxy->source_addr = *str2sa(args[1]);
8579 curproxy->options |= PR_O_BIND_SRC;
8580 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008581 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
8582 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008583 if (curproxy == &defproxy) {
8584 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8585 return -1;
8586 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008587
8588 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008589 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8590 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008591 return -1;
8592 }
8593
8594 preg = calloc(1, sizeof(regex_t));
8595 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008596 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008597 return -1;
8598 }
8599
willy tarreauc1f47532005-12-18 01:08:26 +01008600 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8601 if (err) {
8602 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8603 file, linenum, *err);
8604 return -1;
8605 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008606 }
8607 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
8608 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008609 if (curproxy == &defproxy) {
8610 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8611 return -1;
8612 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008613
8614 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008615 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008616 return -1;
8617 }
8618
8619 preg = calloc(1, sizeof(regex_t));
8620 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008621 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008622 return -1;
8623 }
8624
8625 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8626 }
8627 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
8628 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008629 if (curproxy == &defproxy) {
8630 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8631 return -1;
8632 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008633
8634 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008635 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008636 return -1;
8637 }
8638
8639 preg = calloc(1, sizeof(regex_t));
8640 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008641 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008642 return -1;
8643 }
8644
8645 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8646 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008647 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
8648 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008649 if (curproxy == &defproxy) {
8650 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8651 return -1;
8652 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008653
8654 if (*(args[1]) == 0) {
8655 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8656 return -1;
8657 }
8658
8659 preg = calloc(1, sizeof(regex_t));
8660 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8661 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8662 return -1;
8663 }
8664
8665 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8666 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008667 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
8668 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008669 if (curproxy == &defproxy) {
8670 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8671 return -1;
8672 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008673
8674 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008675 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008676 return -1;
8677 }
8678
8679 preg = calloc(1, sizeof(regex_t));
8680 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008681 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008682 return -1;
8683 }
8684
8685 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8686 }
8687 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
8688 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008689 if (curproxy == &defproxy) {
8690 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8691 return -1;
8692 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008693
8694 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008695 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8696 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008697 return -1;
8698 }
8699
8700 preg = calloc(1, sizeof(regex_t));
8701 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008702 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008703 return -1;
8704 }
8705
willy tarreauc1f47532005-12-18 01:08:26 +01008706 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8707 if (err) {
8708 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8709 file, linenum, *err);
8710 return -1;
8711 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008712 }
8713 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
8714 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008715 if (curproxy == &defproxy) {
8716 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8717 return -1;
8718 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008719
8720 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008721 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008722 return -1;
8723 }
8724
8725 preg = calloc(1, sizeof(regex_t));
8726 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008727 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008728 return -1;
8729 }
8730
8731 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8732 }
8733 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
8734 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008735 if (curproxy == &defproxy) {
8736 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8737 return -1;
8738 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008739
8740 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008741 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008742 return -1;
8743 }
8744
8745 preg = calloc(1, sizeof(regex_t));
8746 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008747 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008748 return -1;
8749 }
8750
8751 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8752 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008753 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
8754 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008755 if (curproxy == &defproxy) {
8756 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8757 return -1;
8758 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008759
8760 if (*(args[1]) == 0) {
8761 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8762 return -1;
8763 }
8764
8765 preg = calloc(1, sizeof(regex_t));
8766 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8767 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8768 return -1;
8769 }
8770
8771 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8772 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008773 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
8774 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008775 if (curproxy == &defproxy) {
8776 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8777 return -1;
8778 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008779
8780 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008781 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008782 return -1;
8783 }
8784
8785 preg = calloc(1, sizeof(regex_t));
8786 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008787 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008788 return -1;
8789 }
8790
8791 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8792 }
8793 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008794 if (curproxy == &defproxy) {
8795 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8796 return -1;
8797 }
8798
willy tarreau9fe663a2005-12-17 13:02:59 +01008799 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008800 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008801 return 0;
8802 }
8803
8804 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008805 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008806 return -1;
8807 }
8808
willy tarreau4302f492005-12-18 01:00:37 +01008809 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
8810 }
8811 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
8812 regex_t *preg;
8813
8814 if (*(args[1]) == 0 || *(args[2]) == 0) {
8815 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8816 file, linenum, args[0]);
8817 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008818 }
willy tarreau4302f492005-12-18 01:00:37 +01008819
8820 preg = calloc(1, sizeof(regex_t));
8821 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8822 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8823 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008824 }
willy tarreau4302f492005-12-18 01:00:37 +01008825
willy tarreauc1f47532005-12-18 01:08:26 +01008826 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8827 if (err) {
8828 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8829 file, linenum, *err);
8830 return -1;
8831 }
willy tarreau4302f492005-12-18 01:00:37 +01008832 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008833 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
8834 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008835 if (curproxy == &defproxy) {
8836 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8837 return -1;
8838 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008839
8840 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008841 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008842 return -1;
8843 }
willy tarreaue39cd132005-12-17 13:00:18 +01008844
willy tarreau9fe663a2005-12-17 13:02:59 +01008845 preg = calloc(1, sizeof(regex_t));
8846 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008847 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008848 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008849 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008850
willy tarreauc1f47532005-12-18 01:08:26 +01008851 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8852 if (err) {
8853 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8854 file, linenum, *err);
8855 return -1;
8856 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008857 }
willy tarreau982249e2005-12-18 00:57:06 +01008858 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
8859 regex_t *preg;
8860 if (curproxy == &defproxy) {
8861 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8862 return -1;
8863 }
8864
8865 if (*(args[1]) == 0) {
8866 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8867 return -1;
8868 }
8869
8870 preg = calloc(1, sizeof(regex_t));
8871 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8872 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8873 return -1;
8874 }
8875
willy tarreauc1f47532005-12-18 01:08:26 +01008876 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8877 if (err) {
8878 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8879 file, linenum, *err);
8880 return -1;
8881 }
willy tarreau982249e2005-12-18 00:57:06 +01008882 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008883 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01008884 regex_t *preg;
8885 if (curproxy == &defproxy) {
8886 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8887 return -1;
8888 }
willy tarreaue39cd132005-12-17 13:00:18 +01008889
willy tarreaua41a8b42005-12-17 14:02:24 +01008890 if (*(args[1]) == 0 || *(args[2]) == 0) {
8891 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8892 file, linenum, args[0]);
8893 return -1;
8894 }
willy tarreaue39cd132005-12-17 13:00:18 +01008895
willy tarreaua41a8b42005-12-17 14:02:24 +01008896 preg = calloc(1, sizeof(regex_t));
8897 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8898 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8899 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008900 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008901
willy tarreauc1f47532005-12-18 01:08:26 +01008902 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8903 if (err) {
8904 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8905 file, linenum, *err);
8906 return -1;
8907 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008908 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008909 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
8910 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008911 if (curproxy == &defproxy) {
8912 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8913 return -1;
8914 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008915
8916 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008917 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008918 return -1;
8919 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008920
willy tarreau9fe663a2005-12-17 13:02:59 +01008921 preg = calloc(1, sizeof(regex_t));
8922 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008923 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008924 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008925 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008926
willy tarreauc1f47532005-12-18 01:08:26 +01008927 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8928 if (err) {
8929 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8930 file, linenum, *err);
8931 return -1;
8932 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008933 }
willy tarreau982249e2005-12-18 00:57:06 +01008934 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
8935 regex_t *preg;
8936 if (curproxy == &defproxy) {
8937 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8938 return -1;
8939 }
8940
8941 if (*(args[1]) == 0) {
8942 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8943 return -1;
8944 }
8945
8946 preg = calloc(1, sizeof(regex_t));
8947 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8948 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8949 return -1;
8950 }
8951
willy tarreauc1f47532005-12-18 01:08:26 +01008952 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8953 if (err) {
8954 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8955 file, linenum, *err);
8956 return -1;
8957 }
willy tarreau982249e2005-12-18 00:57:06 +01008958 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008959 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008960 if (curproxy == &defproxy) {
8961 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8962 return -1;
8963 }
8964
willy tarreau9fe663a2005-12-17 13:02:59 +01008965 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008966 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008967 return 0;
8968 }
8969
8970 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008971 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008972 return -1;
8973 }
8974
8975 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
8976 }
willy tarreauc1f47532005-12-18 01:08:26 +01008977 else if (!strcmp(args[0], "errorloc") ||
8978 !strcmp(args[0], "errorloc302") ||
8979 !strcmp(args[0], "errorloc303")) { /* error location */
8980 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008981 char *err;
8982
willy tarreaueedaa9f2005-12-17 14:08:03 +01008983 // if (curproxy == &defproxy) {
8984 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8985 // return -1;
8986 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01008987
willy tarreau8337c6b2005-12-17 13:41:01 +01008988 if (*(args[2]) == 0) {
8989 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
8990 return -1;
8991 }
8992
8993 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01008994 if (!strcmp(args[0], "errorloc303")) {
8995 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
8996 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
8997 } else {
8998 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
8999 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
9000 }
willy tarreau8337c6b2005-12-17 13:41:01 +01009001
9002 if (errnum == 400) {
9003 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009004 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009005 free(curproxy->errmsg.msg400);
9006 }
9007 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009008 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009009 }
9010 else if (errnum == 403) {
9011 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009012 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009013 free(curproxy->errmsg.msg403);
9014 }
9015 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009016 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009017 }
9018 else if (errnum == 408) {
9019 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009020 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009021 free(curproxy->errmsg.msg408);
9022 }
9023 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009024 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009025 }
9026 else if (errnum == 500) {
9027 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009028 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009029 free(curproxy->errmsg.msg500);
9030 }
9031 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009032 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009033 }
9034 else if (errnum == 502) {
9035 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009036 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009037 free(curproxy->errmsg.msg502);
9038 }
9039 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009040 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009041 }
9042 else if (errnum == 503) {
9043 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009044 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009045 free(curproxy->errmsg.msg503);
9046 }
9047 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009048 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009049 }
9050 else if (errnum == 504) {
9051 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009052 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009053 free(curproxy->errmsg.msg504);
9054 }
9055 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009056 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009057 }
9058 else {
9059 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
9060 free(err);
9061 }
9062 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009063 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01009064 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01009065 return -1;
9066 }
9067 return 0;
9068}
willy tarreaue39cd132005-12-17 13:00:18 +01009069
willy tarreau5cbea6f2005-12-17 12:48:26 +01009070
willy tarreau9fe663a2005-12-17 13:02:59 +01009071/*
9072 * This function reads and parses the configuration file given in the argument.
9073 * returns 0 if OK, -1 if error.
9074 */
9075int readcfgfile(char *file) {
9076 char thisline[256];
9077 char *line;
9078 FILE *f;
9079 int linenum = 0;
9080 char *end;
9081 char *args[MAX_LINE_ARGS];
9082 int arg;
9083 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01009084 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01009085 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01009086
willy tarreau9fe663a2005-12-17 13:02:59 +01009087 struct proxy *curproxy = NULL;
9088 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01009089
willy tarreau9fe663a2005-12-17 13:02:59 +01009090 if ((f=fopen(file,"r")) == NULL)
9091 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01009092
willy tarreaueedaa9f2005-12-17 14:08:03 +01009093 init_default_instance();
9094
willy tarreau9fe663a2005-12-17 13:02:59 +01009095 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
9096 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009097
willy tarreau9fe663a2005-12-17 13:02:59 +01009098 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01009099
willy tarreau9fe663a2005-12-17 13:02:59 +01009100 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01009101 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01009102 line++;
9103
9104 arg = 0;
9105 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01009106
willy tarreau9fe663a2005-12-17 13:02:59 +01009107 while (*line && arg < MAX_LINE_ARGS) {
9108 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
9109 * C equivalent value. Other combinations left unchanged (eg: \1).
9110 */
9111 if (*line == '\\') {
9112 int skip = 0;
9113 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
9114 *line = line[1];
9115 skip = 1;
9116 }
9117 else if (line[1] == 'r') {
9118 *line = '\r';
9119 skip = 1;
9120 }
9121 else if (line[1] == 'n') {
9122 *line = '\n';
9123 skip = 1;
9124 }
9125 else if (line[1] == 't') {
9126 *line = '\t';
9127 skip = 1;
9128 }
willy tarreauc1f47532005-12-18 01:08:26 +01009129 else if (line[1] == 'x') {
9130 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
9131 unsigned char hex1, hex2;
9132 hex1 = toupper(line[2]) - '0';
9133 hex2 = toupper(line[3]) - '0';
9134 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
9135 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
9136 *line = (hex1<<4) + hex2;
9137 skip = 3;
9138 }
9139 else {
9140 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
9141 return -1;
9142 }
9143 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009144 if (skip) {
9145 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
9146 end -= skip;
9147 }
9148 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01009149 }
willy tarreaua1598082005-12-17 13:08:06 +01009150 else if (*line == '#' || *line == '\n' || *line == '\r') {
9151 /* end of string, end of loop */
9152 *line = 0;
9153 break;
9154 }
willy tarreauc29948c2005-12-17 13:10:27 +01009155 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009156 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01009157 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01009158 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01009159 line++;
9160 args[++arg] = line;
9161 }
9162 else {
9163 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01009164 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009165 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009166
willy tarreau9fe663a2005-12-17 13:02:59 +01009167 /* empty line */
9168 if (!**args)
9169 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01009170
willy tarreau9fe663a2005-12-17 13:02:59 +01009171 /* zero out remaining args */
9172 while (++arg < MAX_LINE_ARGS) {
9173 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009174 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009175
willy tarreaua41a8b42005-12-17 14:02:24 +01009176 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01009177 confsect = CFG_LISTEN;
9178 else if (!strcmp(args[0], "global")) /* global config */
9179 confsect = CFG_GLOBAL;
9180 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01009181
willy tarreau9fe663a2005-12-17 13:02:59 +01009182 switch (confsect) {
9183 case CFG_LISTEN:
9184 if (cfg_parse_listen(file, linenum, args) < 0)
9185 return -1;
9186 break;
9187 case CFG_GLOBAL:
9188 if (cfg_parse_global(file, linenum, args) < 0)
9189 return -1;
9190 break;
9191 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01009192 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009193 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01009194 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009195
9196
willy tarreau0f7af912005-12-17 12:21:26 +01009197 }
9198 fclose(f);
9199
9200 /*
9201 * Now, check for the integrity of all that we have collected.
9202 */
9203
Willy TARREAU3759f982006-03-01 22:44:17 +01009204 /* will be needed further to delay some tasks */
9205 tv_now(&now);
9206
willy tarreau0f7af912005-12-17 12:21:26 +01009207 if ((curproxy = proxy) == NULL) {
9208 Alert("parsing %s : no <listen> line. Nothing to do !\n",
9209 file);
9210 return -1;
9211 }
9212
9213 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01009214 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01009215 curproxy = curproxy->next;
9216 continue;
9217 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009218
9219 if (curproxy->listen == NULL) {
9220 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);
9221 cfgerr++;
9222 }
9223 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01009224 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01009225 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01009226 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
9227 file, curproxy->id);
9228 cfgerr++;
9229 }
9230 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
9231 if (curproxy->options & PR_O_TRANSP) {
9232 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
9233 file, curproxy->id);
9234 cfgerr++;
9235 }
willy tarreau38d79062006-05-21 14:47:13 +02009236#ifdef WE_DONT_SUPPORT_SERVERLESS_LISTENERS
willy tarreau5cbea6f2005-12-17 12:48:26 +01009237 else if (curproxy->srv == NULL) {
9238 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
9239 file, curproxy->id);
9240 cfgerr++;
9241 }
willy tarreau38d79062006-05-21 14:47:13 +02009242#endif
willy tarreaua1598082005-12-17 13:08:06 +01009243 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01009244 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
9245 file, curproxy->id);
9246 }
9247 }
9248 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01009249 if (curproxy->cookie_name != NULL) {
9250 Warning("parsing %s : cookie will be ignored for listener %s.\n",
9251 file, curproxy->id);
9252 }
9253 if ((newsrv = curproxy->srv) != NULL) {
9254 Warning("parsing %s : servers will be ignored for listener %s.\n",
9255 file, curproxy->id);
9256 }
willy tarreaue39cd132005-12-17 13:00:18 +01009257 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01009258 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
9259 file, curproxy->id);
9260 }
willy tarreaue39cd132005-12-17 13:00:18 +01009261 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01009262 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
9263 file, curproxy->id);
9264 }
9265 }
9266 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
9267 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
9268 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
9269 file, curproxy->id);
9270 cfgerr++;
9271 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009272 }
willy tarreaue3f023f2006-04-08 21:52:24 +02009273
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009274 /* first, we will invert the servers list order */
9275 newsrv = NULL;
9276 while (curproxy->srv) {
9277 struct server *next;
9278
9279 next = curproxy->srv->next;
9280 curproxy->srv->next = newsrv;
9281 newsrv = curproxy->srv;
9282 if (!next)
9283 break;
9284 curproxy->srv = next;
9285 }
9286
9287 /* now, newsrv == curproxy->srv */
9288 if (newsrv) {
9289 struct server *srv;
9290 int pgcd;
9291 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02009292
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009293 /* We will factor the weights to reduce the table,
9294 * using Euclide's largest common divisor algorithm
9295 */
9296 pgcd = newsrv->uweight + 1;
9297 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
9298 int t, w;
9299
9300 w = srv->uweight + 1;
9301 while (w) {
9302 t = pgcd % w;
9303 pgcd = w;
9304 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02009305 }
willy tarreau0f7af912005-12-17 12:21:26 +01009306 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009307
9308 act = bck = 0;
9309 for (srv = newsrv; srv; srv = srv->next) {
9310 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
9311 if (srv->state & SRV_BACKUP)
9312 bck += srv->eweight + 1;
9313 else
9314 act += srv->eweight + 1;
9315 }
9316
9317 /* this is the largest map we will ever need for this servers list */
9318 if (act < bck)
9319 act = bck;
9320
9321 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
9322 /* recounts servers and their weights */
9323 recount_servers(curproxy);
9324 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01009325 }
willy tarreau25c4ea52005-12-18 00:49:49 +01009326
9327 if (curproxy->options & PR_O_LOGASAP)
9328 curproxy->to_log &= ~LW_BYTES;
9329
willy tarreau8337c6b2005-12-17 13:41:01 +01009330 if (curproxy->errmsg.msg400 == NULL) {
9331 curproxy->errmsg.msg400 = (char *)HTTP_400;
9332 curproxy->errmsg.len400 = strlen(HTTP_400);
9333 }
9334 if (curproxy->errmsg.msg403 == NULL) {
9335 curproxy->errmsg.msg403 = (char *)HTTP_403;
9336 curproxy->errmsg.len403 = strlen(HTTP_403);
9337 }
9338 if (curproxy->errmsg.msg408 == NULL) {
9339 curproxy->errmsg.msg408 = (char *)HTTP_408;
9340 curproxy->errmsg.len408 = strlen(HTTP_408);
9341 }
9342 if (curproxy->errmsg.msg500 == NULL) {
9343 curproxy->errmsg.msg500 = (char *)HTTP_500;
9344 curproxy->errmsg.len500 = strlen(HTTP_500);
9345 }
9346 if (curproxy->errmsg.msg502 == NULL) {
9347 curproxy->errmsg.msg502 = (char *)HTTP_502;
9348 curproxy->errmsg.len502 = strlen(HTTP_502);
9349 }
9350 if (curproxy->errmsg.msg503 == NULL) {
9351 curproxy->errmsg.msg503 = (char *)HTTP_503;
9352 curproxy->errmsg.len503 = strlen(HTTP_503);
9353 }
9354 if (curproxy->errmsg.msg504 == NULL) {
9355 curproxy->errmsg.msg504 = (char *)HTTP_504;
9356 curproxy->errmsg.len504 = strlen(HTTP_504);
9357 }
Willy TARREAU3759f982006-03-01 22:44:17 +01009358
willy tarreau59a6cc22006-05-12 01:29:08 +02009359 /*
9360 * If this server supports a maxconn parameter, it needs a dedicated
9361 * tasks to fill the emptied slots when a connection leaves.
9362 */
9363 newsrv = curproxy->srv;
9364 while (newsrv != NULL) {
9365 if (newsrv->maxconn > 0) {
9366 struct task *t;
9367
9368 if ((t = pool_alloc(task)) == NULL) {
9369 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
9370 return -1;
9371 }
9372
9373 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
9374 t->wq = LIST_HEAD(wait_queue[1]); /* already assigned to the eternity queue */
9375 t->state = TASK_IDLE;
9376 t->process = process_srv_queue;
9377 t->context = newsrv;
9378 newsrv->queue_mgt = t;
9379
9380 /* never run it unless specifically woken up */
9381 tv_eternity(&t->expire);
9382 task_queue(t);
9383 }
9384 newsrv = newsrv->next;
9385 }
9386
Willy TARREAU3759f982006-03-01 22:44:17 +01009387 /* now we'll start this proxy's health checks if any */
9388 /* 1- count the checkers to run simultaneously */
9389 nbchk = 0;
9390 mininter = 0;
9391 newsrv = curproxy->srv;
9392 while (newsrv != NULL) {
9393 if (newsrv->state & SRV_CHECKED) {
9394 if (!mininter || mininter > newsrv->inter)
9395 mininter = newsrv->inter;
9396 nbchk++;
9397 }
9398 newsrv = newsrv->next;
9399 }
9400
9401 /* 2- start them as far as possible from each others while respecting
9402 * their own intervals. For this, we will start them after their own
9403 * interval added to the min interval divided by the number of servers,
9404 * weighted by the server's position in the list.
9405 */
9406 if (nbchk > 0) {
9407 struct task *t;
9408 int srvpos;
9409
9410 newsrv = curproxy->srv;
9411 srvpos = 0;
9412 while (newsrv != NULL) {
9413 /* should this server be checked ? */
9414 if (newsrv->state & SRV_CHECKED) {
9415 if ((t = pool_alloc(task)) == NULL) {
9416 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
9417 return -1;
9418 }
9419
9420 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02009421 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
Willy TARREAU3759f982006-03-01 22:44:17 +01009422 t->state = TASK_IDLE;
9423 t->process = process_chk;
9424 t->context = newsrv;
9425
9426 /* check this every ms */
9427 tv_delayfrom(&t->expire, &now,
9428 newsrv->inter + mininter * srvpos / nbchk);
9429 task_queue(t);
9430 //task_wakeup(&rq, t);
9431 srvpos++;
9432 }
9433 newsrv = newsrv->next;
9434 }
9435 }
9436
willy tarreau0f7af912005-12-17 12:21:26 +01009437 curproxy = curproxy->next;
9438 }
9439 if (cfgerr > 0) {
9440 Alert("Errors found in configuration file, aborting.\n");
9441 return -1;
9442 }
9443 else
9444 return 0;
9445}
9446
9447
9448/*
9449 * This function initializes all the necessary variables. It only returns
9450 * if everything is OK. If something fails, it exits.
9451 */
9452void init(int argc, char **argv) {
9453 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01009454 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01009455 char *old_argv = *argv;
9456 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009457 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009458
9459 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01009460 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01009461 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01009462 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01009463 exit(1);
9464 }
9465
willy tarreau746e26b2006-03-25 11:14:35 +01009466#ifdef HAPROXY_MEMMAX
9467 global.rlimit_memmax = HAPROXY_MEMMAX;
9468#endif
9469
Willy TARREAUa9e75f62006-03-01 22:27:48 +01009470 /* initialize the libc's localtime structures once for all so that we
9471 * won't be missing memory if we want to send alerts under OOM conditions.
9472 */
9473 tv_now(&now);
9474 localtime(&now.tv_sec);
willy tarreaue0331262006-05-15 03:02:46 +02009475 start_date = now;
Willy TARREAUa9e75f62006-03-01 22:27:48 +01009476
willy tarreau4302f492005-12-18 01:00:37 +01009477 /* initialize the log header encoding map : '{|}"#' should be encoded with
9478 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
9479 * URL encoding only requires '"', '#' to be encoded as well as non-
9480 * printable characters above.
9481 */
9482 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
9483 memset(url_encode_map, 0, sizeof(url_encode_map));
9484 for (i = 0; i < 32; i++) {
9485 FD_SET(i, hdr_encode_map);
9486 FD_SET(i, url_encode_map);
9487 }
9488 for (i = 127; i < 256; i++) {
9489 FD_SET(i, hdr_encode_map);
9490 FD_SET(i, url_encode_map);
9491 }
9492
9493 tmp = "\"#{|}";
9494 while (*tmp) {
9495 FD_SET(*tmp, hdr_encode_map);
9496 tmp++;
9497 }
9498
9499 tmp = "\"#";
9500 while (*tmp) {
9501 FD_SET(*tmp, url_encode_map);
9502 tmp++;
9503 }
9504
willy tarreau64a3cc32005-12-18 01:13:11 +01009505 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
9506#if defined(ENABLE_POLL)
9507 cfg_polling_mechanism |= POLL_USE_POLL;
9508#endif
9509#if defined(ENABLE_EPOLL)
9510 cfg_polling_mechanism |= POLL_USE_EPOLL;
9511#endif
9512
willy tarreau0f7af912005-12-17 12:21:26 +01009513 pid = getpid();
9514 progname = *argv;
9515 while ((tmp = strchr(progname, '/')) != NULL)
9516 progname = tmp + 1;
9517
9518 argc--; argv++;
9519 while (argc > 0) {
9520 char *flag;
9521
9522 if (**argv == '-') {
9523 flag = *argv+1;
9524
9525 /* 1 arg */
9526 if (*flag == 'v') {
9527 display_version();
9528 exit(0);
9529 }
willy tarreau1c2ad212005-12-18 01:11:29 +01009530#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009531 else if (*flag == 'd' && flag[1] == 'e')
9532 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009533#endif
9534#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009535 else if (*flag == 'd' && flag[1] == 'p')
9536 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009537#endif
willy tarreau982249e2005-12-18 00:57:06 +01009538 else if (*flag == 'V')
9539 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009540 else if (*flag == 'd' && flag[1] == 'b')
9541 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01009542 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01009543 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01009544 else if (*flag == 'c')
9545 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01009546 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01009547 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009548 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01009549 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01009550 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
9551 /* list of pids to finish ('f') or terminate ('t') */
9552
9553 if (flag[1] == 'f')
9554 oldpids_sig = SIGUSR1; /* finish then exit */
9555 else
9556 oldpids_sig = SIGTERM; /* terminate immediately */
9557 argv++; argc--;
9558
9559 if (argc > 0) {
9560 oldpids = calloc(argc, sizeof(int));
9561 while (argc > 0) {
9562 oldpids[nb_oldpids] = atol(*argv);
9563 if (oldpids[nb_oldpids] <= 0)
9564 usage(old_argv);
9565 argc--; argv++;
9566 nb_oldpids++;
9567 }
9568 }
9569 }
willy tarreau2c513732006-04-15 19:25:16 +02009570#if STATTIME > 0
9571 else if (*flag == 's')
9572 arg_mode |= MODE_STATS;
9573 else if (*flag == 'l')
9574 arg_mode |= MODE_LOG;
9575#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009576 else { /* >=2 args */
9577 argv++; argc--;
9578 if (argc == 0)
9579 usage(old_argv);
9580
9581 switch (*flag) {
9582 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01009583 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01009584 case 'N' : cfg_maxpconn = atol(*argv); break;
9585 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009586 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01009587 default: usage(old_argv);
9588 }
9589 }
9590 }
9591 else
9592 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01009593 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01009594 }
9595
willy tarreaud0fb4652005-12-18 01:32:04 +01009596 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009597 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
9598 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01009599
willy tarreau0f7af912005-12-17 12:21:26 +01009600 if (!cfg_cfgfile)
9601 usage(old_argv);
9602
9603 gethostname(hostname, MAX_HOSTNAME_LEN);
9604
willy tarreau12350152005-12-18 01:03:27 +01009605 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01009606 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01009607 if (readcfgfile(cfg_cfgfile) < 0) {
9608 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
9609 exit(1);
9610 }
willy tarreau12350152005-12-18 01:03:27 +01009611 if (have_appsession)
9612 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01009613
willy tarreau982249e2005-12-18 00:57:06 +01009614 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01009615 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
9616 exit(0);
9617 }
9618
willy tarreau9fe663a2005-12-17 13:02:59 +01009619 if (cfg_maxconn > 0)
9620 global.maxconn = cfg_maxconn;
9621
willy tarreaufe2c5c12005-12-17 14:14:34 +01009622 if (cfg_pidfile) {
9623 if (global.pidfile)
9624 free(global.pidfile);
9625 global.pidfile = strdup(cfg_pidfile);
9626 }
9627
willy tarreau9fe663a2005-12-17 13:02:59 +01009628 if (global.maxconn == 0)
9629 global.maxconn = DEFAULT_MAXCONN;
9630
Willy TARREAU203b0b62006-03-12 18:00:28 +01009631 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01009632
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009633 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009634 /* command line debug mode inhibits configuration mode */
9635 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
9636 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009637 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
9638 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01009639
9640 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
9641 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
9642 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
9643 }
9644
9645 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009646 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
9647 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01009648 global.nbproc = 1;
9649 }
9650
9651 if (global.nbproc < 1)
9652 global.nbproc = 1;
9653
willy tarreau0f7af912005-12-17 12:21:26 +01009654 StaticReadEvent = (fd_set *)calloc(1,
9655 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01009656 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01009657 StaticWriteEvent = (fd_set *)calloc(1,
9658 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01009659 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01009660
9661 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01009662 sizeof(struct fdtab) * (global.maxsock));
9663 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01009664 fdtab[i].state = FD_STCLOSE;
9665 }
9666}
9667
9668/*
willy tarreau41310e72006-03-25 18:17:56 +01009669 * this function starts all the proxies. Its return value is composed from
9670 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
9671 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01009672 */
willy tarreau41310e72006-03-25 18:17:56 +01009673int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01009674 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01009675 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01009676 int err = ERR_NONE;
9677 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01009678
9679 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01009680 if (curproxy->state != PR_STNEW)
9681 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01009682
willy tarreau41310e72006-03-25 18:17:56 +01009683 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01009684 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01009685 if (listener->fd != -1)
9686 continue; /* already initialized */
9687
9688 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
9689 if (verbose)
9690 Alert("cannot create listening socket for proxy %s. Aborting.\n",
9691 curproxy->id);
9692 err |= ERR_RETRYABLE;
9693 pxerr |= 1;
9694 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009695 }
willy tarreau0f7af912005-12-17 12:21:26 +01009696
willy tarreaua41a8b42005-12-17 14:02:24 +01009697 if (fd >= global.maxsock) {
9698 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
9699 curproxy->id);
9700 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009701 err |= ERR_FATAL;
9702 pxerr |= 1;
9703 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009704 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009705
willy tarreaua41a8b42005-12-17 14:02:24 +01009706 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
9707 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
9708 (char *) &one, sizeof(one)) == -1)) {
9709 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
9710 curproxy->id);
9711 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009712 err |= ERR_FATAL;
9713 pxerr |= 1;
9714 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009715 }
willy tarreau0f7af912005-12-17 12:21:26 +01009716
willy tarreaua41a8b42005-12-17 14:02:24 +01009717 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
9718 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
9719 curproxy->id);
9720 }
willy tarreau0f7af912005-12-17 12:21:26 +01009721
willy tarreaufac1a862006-05-21 10:20:28 +02009722#ifdef SO_REUSEPORT
9723 /* OpenBSD supports this. As it's present in old libc versions of Linux,
9724 * it might return an error that we will silently ignore.
9725 */
9726 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one));
9727#endif
willy tarreaua41a8b42005-12-17 14:02:24 +01009728 if (bind(fd,
9729 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01009730 listener->addr.ss_family == AF_INET6 ?
9731 sizeof(struct sockaddr_in6) :
9732 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009733 if (verbose)
9734 Alert("cannot bind socket for proxy %s. Aborting.\n",
9735 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009736 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009737 err |= ERR_RETRYABLE;
9738 pxerr |= 1;
9739 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009740 }
willy tarreau0f7af912005-12-17 12:21:26 +01009741
willy tarreaua41a8b42005-12-17 14:02:24 +01009742 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009743 if (verbose)
9744 Alert("cannot listen to socket for proxy %s. Aborting.\n",
9745 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009746 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009747 err |= ERR_RETRYABLE;
9748 pxerr |= 1;
9749 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009750 }
willy tarreau0f7af912005-12-17 12:21:26 +01009751
willy tarreau41310e72006-03-25 18:17:56 +01009752 /* the socket is ready */
9753 listener->fd = fd;
9754
willy tarreaua41a8b42005-12-17 14:02:24 +01009755 /* the function for the accept() event */
9756 fdtab[fd].read = &event_accept;
9757 fdtab[fd].write = NULL; /* never called */
9758 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01009759 fdtab[fd].state = FD_STLISTEN;
9760 FD_SET(fd, StaticReadEvent);
9761 fd_insert(fd);
9762 listeners++;
9763 }
willy tarreau41310e72006-03-25 18:17:56 +01009764
9765 if (!pxerr) {
9766 curproxy->state = PR_STRUN;
9767 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
9768 }
willy tarreau0f7af912005-12-17 12:21:26 +01009769 }
willy tarreau41310e72006-03-25 18:17:56 +01009770
9771 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01009772}
9773
willy tarreaub952e1d2005-12-18 01:31:20 +01009774int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01009775
9776 appsess *temp1,*temp2;
9777 temp1 = (appsess *)key1;
9778 temp2 = (appsess *)key2;
9779
9780 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
9781 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
9782
9783 return (strcmp(temp1->sessid,temp2->sessid) == 0);
9784}/* end match_str */
9785
willy tarreaub952e1d2005-12-18 01:31:20 +01009786void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01009787 appsess *temp1;
9788
9789 //printf("destroy called\n");
9790 temp1 = (appsess *)data;
9791
9792 if (temp1->sessid)
9793 pool_free_to(apools.sessid, temp1->sessid);
9794
9795 if (temp1->serverid)
9796 pool_free_to(apools.serverid, temp1->serverid);
9797
9798 pool_free(appsess, temp1);
9799} /* end destroy */
9800
9801void appsession_cleanup( void )
9802{
9803 struct proxy *p = proxy;
9804
9805 while(p) {
9806 chtbl_destroy(&(p->htbl_proxy));
9807 p = p->next;
9808 }
9809}/* end appsession_cleanup() */
9810
9811void pool_destroy(void **pool)
9812{
9813 void *temp, *next;
9814 next = pool;
9815 while (next) {
9816 temp = next;
9817 next = *(void **)temp;
9818 free(temp);
9819 }
9820}/* end pool_destroy() */
9821
willy tarreaub952e1d2005-12-18 01:31:20 +01009822void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01009823 struct proxy *p = proxy;
9824 struct cap_hdr *h,*h_next;
9825 struct server *s,*s_next;
9826 struct listener *l,*l_next;
9827
9828 while (p) {
9829 if (p->id)
9830 free(p->id);
9831
9832 if (p->check_req)
9833 free(p->check_req);
9834
9835 if (p->cookie_name)
9836 free(p->cookie_name);
9837
9838 if (p->capture_name)
9839 free(p->capture_name);
9840
9841 /* only strup if the user have set in config.
9842 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01009843 if (p->errmsg.msg400) free(p->errmsg.msg400);
9844 if (p->errmsg.msg403) free(p->errmsg.msg403);
9845 if (p->errmsg.msg408) free(p->errmsg.msg408);
9846 if (p->errmsg.msg500) free(p->errmsg.msg500);
9847 if (p->errmsg.msg502) free(p->errmsg.msg502);
9848 if (p->errmsg.msg503) free(p->errmsg.msg503);
9849 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01009850 */
9851 if (p->appsession_name)
9852 free(p->appsession_name);
9853
9854 h = p->req_cap;
9855 while (h) {
9856 h_next = h->next;
9857 if (h->name)
9858 free(h->name);
9859 pool_destroy(h->pool);
9860 free(h);
9861 h = h_next;
9862 }/* end while(h) */
9863
9864 h = p->rsp_cap;
9865 while (h) {
9866 h_next = h->next;
9867 if (h->name)
9868 free(h->name);
9869
9870 pool_destroy(h->pool);
9871 free(h);
9872 h = h_next;
9873 }/* end while(h) */
9874
9875 s = p->srv;
9876 while (s) {
9877 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01009878 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01009879 free(s->id);
9880
willy tarreaub952e1d2005-12-18 01:31:20 +01009881 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01009882 free(s->cookie);
9883
9884 free(s);
9885 s = s_next;
9886 }/* end while(s) */
9887
9888 l = p->listen;
9889 while (l) {
9890 l_next = l->next;
9891 free(l);
9892 l = l_next;
9893 }/* end while(l) */
9894
9895 pool_destroy((void **) p->req_cap_pool);
9896 pool_destroy((void **) p->rsp_cap_pool);
9897 p = p->next;
9898 }/* end while(p) */
9899
9900 if (global.chroot) free(global.chroot);
9901 if (global.pidfile) free(global.pidfile);
9902
willy tarreau12350152005-12-18 01:03:27 +01009903 if (StaticReadEvent) free(StaticReadEvent);
9904 if (StaticWriteEvent) free(StaticWriteEvent);
9905 if (fdtab) free(fdtab);
9906
9907 pool_destroy(pool_session);
9908 pool_destroy(pool_buffer);
9909 pool_destroy(pool_fdtab);
9910 pool_destroy(pool_requri);
9911 pool_destroy(pool_task);
9912 pool_destroy(pool_capture);
9913 pool_destroy(pool_appsess);
9914
9915 if (have_appsession) {
9916 pool_destroy(apools.serverid);
9917 pool_destroy(apools.sessid);
9918 }
9919} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01009920
willy tarreau41310e72006-03-25 18:17:56 +01009921/* sends the signal <sig> to all pids found in <oldpids> */
9922static void tell_old_pids(int sig) {
9923 int p;
9924 for (p = 0; p < nb_oldpids; p++)
9925 kill(oldpids[p], sig);
9926}
9927
willy tarreau0f7af912005-12-17 12:21:26 +01009928int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01009929 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01009930 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009931 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009932 init(argc, argv);
9933
willy tarreau0f7af912005-12-17 12:21:26 +01009934 signal(SIGQUIT, dump);
9935 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01009936 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01009937#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01009938 signal(SIGINT, sig_int);
9939 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01009940#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009941
9942 /* on very high loads, a sigpipe sometimes happen just between the
9943 * getsockopt() which tells "it's OK to write", and the following write :-(
9944 */
willy tarreau3242e862005-12-17 12:27:53 +01009945#ifndef MSG_NOSIGNAL
9946 signal(SIGPIPE, SIG_IGN);
9947#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009948
willy tarreau41310e72006-03-25 18:17:56 +01009949 /* We will loop at most 100 times with 10 ms delay each time.
9950 * That's at most 1 second. We only send a signal to old pids
9951 * if we cannot grab at least one port.
9952 */
9953 retry = MAX_START_RETRIES;
9954 err = ERR_NONE;
9955 while (retry >= 0) {
9956 struct timeval w;
9957 err = start_proxies(retry == 0 || nb_oldpids == 0);
9958 if (err != ERR_RETRYABLE)
9959 break;
9960 if (nb_oldpids == 0)
9961 break;
9962
Willy TARREAU007aa462006-05-14 09:55:23 +02009963 /* FIXME-20060514: Solaris and OpenBSD do not support shutdown() on
9964 * listening sockets. So on those platforms, it would be wiser to
9965 * simply send SIGUSR1, which will not be undoable.
9966 */
willy tarreau41310e72006-03-25 18:17:56 +01009967 tell_old_pids(SIGTTOU);
9968 /* give some time to old processes to stop listening */
9969 w.tv_sec = 0;
9970 w.tv_usec = 10*1000;
9971 select(0, NULL, NULL, NULL, &w);
9972 retry--;
9973 }
9974
9975 /* Note: start_proxies() sends an alert when it fails. */
9976 if (err != ERR_NONE) {
9977 if (retry != MAX_START_RETRIES && nb_oldpids)
9978 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01009979 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01009980 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009981
9982 if (listeners == 0) {
9983 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009984 /* Note: we don't have to send anything to the old pids because we
9985 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01009986 exit(1);
9987 }
9988
willy tarreaudbd3bef2006-01-20 19:35:18 +01009989 /* prepare pause/play signals */
9990 signal(SIGTTOU, sig_pause);
9991 signal(SIGTTIN, sig_listen);
9992
Willy TARREAUe3283d12006-03-01 22:15:29 +01009993 if (global.mode & MODE_DAEMON) {
9994 global.mode &= ~MODE_VERBOSE;
9995 global.mode |= MODE_QUIET;
9996 }
9997
willy tarreaud0fb4652005-12-18 01:32:04 +01009998 /* MODE_QUIET can inhibit alerts and warnings below this line */
9999
10000 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +010010001 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +010010002 /* detach from the tty */
10003 fclose(stdin); fclose(stdout); fclose(stderr);
10004 close(0); close(1); close(2);
10005 }
willy tarreau0f7af912005-12-17 12:21:26 +010010006
willy tarreaufe2c5c12005-12-17 14:14:34 +010010007 /* open log & pid files before the chroot */
10008 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
10009 int pidfd;
10010 unlink(global.pidfile);
10011 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
10012 if (pidfd < 0) {
10013 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +010010014 if (nb_oldpids)
10015 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +010010016 exit(1);
10017 }
10018 pidfile = fdopen(pidfd, "w");
10019 }
willy tarreau9fe663a2005-12-17 13:02:59 +010010020
10021 /* chroot if needed */
10022 if (global.chroot != NULL) {
10023 if (chroot(global.chroot) == -1) {
10024 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +010010025 if (nb_oldpids)
10026 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +010010027 }
10028 chdir("/");
10029 }
10030
willy tarreaub1285d52005-12-18 01:20:14 +010010031 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +010010032 if (!global.rlimit_nofile)
10033 global.rlimit_nofile = global.maxsock;
10034
willy tarreaub1285d52005-12-18 01:20:14 +010010035 if (global.rlimit_nofile) {
10036 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
10037 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
10038 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
10039 }
willy tarreau746e26b2006-03-25 11:14:35 +010010040 }
10041
10042 if (global.rlimit_memmax) {
10043 limit.rlim_cur = limit.rlim_max =
10044 global.rlimit_memmax * 1048576 / global.nbproc;
10045#ifdef RLIMIT_AS
10046 if (setrlimit(RLIMIT_AS, &limit) == -1) {
10047 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
10048 argv[0], global.rlimit_memmax);
10049 }
10050#else
10051 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
10052 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
10053 argv[0], global.rlimit_memmax);
10054 }
10055#endif
willy tarreaub1285d52005-12-18 01:20:14 +010010056 }
10057
willy tarreau41310e72006-03-25 18:17:56 +010010058 if (nb_oldpids)
10059 tell_old_pids(oldpids_sig);
10060
10061 /* Note that any error at this stage will be fatal because we will not
10062 * be able to restart the old pids.
10063 */
10064
willy tarreau9fe663a2005-12-17 13:02:59 +010010065 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +010010066 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +010010067 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
10068 exit(1);
10069 }
10070
willy tarreau036e1ce2005-12-17 13:46:33 +010010071 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +010010072 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
10073 exit(1);
10074 }
10075
willy tarreaub1285d52005-12-18 01:20:14 +010010076 /* check ulimits */
10077 limit.rlim_cur = limit.rlim_max = 0;
10078 getrlimit(RLIMIT_NOFILE, &limit);
10079 if (limit.rlim_cur < global.maxsock) {
10080 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",
10081 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
10082 }
10083
willy tarreau9fe663a2005-12-17 13:02:59 +010010084 if (global.mode & MODE_DAEMON) {
10085 int ret = 0;
10086 int proc;
10087
10088 /* the father launches the required number of processes */
10089 for (proc = 0; proc < global.nbproc; proc++) {
10090 ret = fork();
10091 if (ret < 0) {
10092 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +010010093 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +010010094 exit(1); /* there has been an error */
10095 }
10096 else if (ret == 0) /* child breaks here */
10097 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +010010098 if (pidfile != NULL) {
10099 fprintf(pidfile, "%d\n", ret);
10100 fflush(pidfile);
10101 }
willy tarreau9fe663a2005-12-17 13:02:59 +010010102 }
willy tarreaufe2c5c12005-12-17 14:14:34 +010010103 /* close the pidfile both in children and father */
10104 if (pidfile != NULL)
10105 fclose(pidfile);
10106 free(global.pidfile);
10107
willy tarreau9fe663a2005-12-17 13:02:59 +010010108 if (proc == global.nbproc)
10109 exit(0); /* parent must leave */
10110
willy tarreau750a4722005-12-17 13:21:24 +010010111 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
10112 * that we can detach from the TTY. We MUST NOT do it in other cases since
10113 * it would have already be done, and 0-2 would have been affected to listening
10114 * sockets
10115 */
10116 if (!(global.mode & MODE_QUIET)) {
10117 /* detach from the tty */
10118 fclose(stdin); fclose(stdout); fclose(stderr);
10119 close(0); close(1); close(2); /* close all fd's */
10120 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
10121 }
willy tarreaua1598082005-12-17 13:08:06 +010010122 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +010010123 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +010010124 }
10125
willy tarreau1c2ad212005-12-18 01:11:29 +010010126#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +010010127 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010128 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
10129 epoll_loop(POLL_LOOP_ACTION_RUN);
10130 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010131 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010132 }
10133 else {
willy tarreau64a3cc32005-12-18 01:13:11 +010010134 Warning("epoll() is not available. Using poll()/select() instead.\n");
10135 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010136 }
10137 }
10138#endif
10139
10140#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +010010141 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010142 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
10143 poll_loop(POLL_LOOP_ACTION_RUN);
10144 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010145 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010146 }
10147 else {
10148 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +010010149 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010150 }
10151 }
10152#endif
willy tarreau64a3cc32005-12-18 01:13:11 +010010153 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010154 if (select_loop(POLL_LOOP_ACTION_INIT)) {
10155 select_loop(POLL_LOOP_ACTION_RUN);
10156 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010157 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +010010158 }
10159 }
10160
willy tarreau0f7af912005-12-17 12:21:26 +010010161
willy tarreau12350152005-12-18 01:03:27 +010010162 /* Free all Hash Keys and all Hash elements */
10163 appsession_cleanup();
10164 /* Do some cleanup */
10165 deinit();
10166
willy tarreau0f7af912005-12-17 12:21:26 +010010167 exit(0);
10168}
willy tarreau12350152005-12-18 01:03:27 +010010169
10170#if defined(DEBUG_HASH)
10171static void print_table(const CHTbl *htbl) {
10172
10173 ListElmt *element;
10174 int i;
10175 appsess *asession;
10176
10177 /*****************************************************************************
10178 * *
10179 * Display the chained hash table. *
10180 * *
10181 *****************************************************************************/
10182
10183 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
10184
10185 for (i = 0; i < TBLSIZ; i++) {
10186 fprintf(stdout, "Bucket[%03d]\n", i);
10187
10188 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
10189 //fprintf(stdout, "%c", *(char *)list_data(element));
10190 asession = (appsess *)list_data(element);
10191 fprintf(stdout, "ELEM :%s:", asession->sessid);
10192 fprintf(stdout, " Server :%s: \n", asession->serverid);
10193 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
10194 }
10195
10196 fprintf(stdout, "\n");
10197 }
10198 return;
10199} /* end print_table */
10200#endif
10201
10202static int appsession_init(void)
10203{
10204 static int initialized = 0;
10205 int idlen;
10206 struct server *s;
10207 struct proxy *p = proxy;
10208
10209 if (!initialized) {
10210 if (!appsession_task_init()) {
10211 apools.sessid = NULL;
10212 apools.serverid = NULL;
10213 apools.ser_waste = 0;
10214 apools.ser_use = 0;
10215 apools.ser_msize = sizeof(void *);
10216 apools.ses_waste = 0;
10217 apools.ses_use = 0;
10218 apools.ses_msize = sizeof(void *);
10219 while (p) {
10220 s = p->srv;
10221 if (apools.ses_msize < p->appsession_len)
10222 apools.ses_msize = p->appsession_len;
10223 while (s) {
10224 idlen = strlen(s->id);
10225 if (apools.ser_msize < idlen)
10226 apools.ser_msize = idlen;
10227 s = s->next;
10228 }
10229 p = p->next;
10230 }
10231 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
10232 apools.ses_msize ++;
10233 }
10234 else {
10235 fprintf(stderr, "appsession_task_init failed\n");
10236 return -1;
10237 }
10238 initialized ++;
10239 }
10240 return 0;
10241}
10242
10243static int appsession_task_init(void)
10244{
10245 static int initialized = 0;
10246 struct task *t;
10247 if (!initialized) {
10248 if ((t = pool_alloc(task)) == NULL)
10249 return -1;
10250 t->next = t->prev = t->rqnext = NULL;
willy tarreau5e698ef2006-05-02 14:51:00 +020010251 t->wq = LIST_HEAD(wait_queue[0]);
willy tarreau12350152005-12-18 01:03:27 +010010252 t->state = TASK_IDLE;
10253 t->context = NULL;
10254 tv_delayfrom(&t->expire, &now, TBLCHKINT);
10255 task_queue(t);
10256 t->process = appsession_refresh;
10257 initialized ++;
10258 }
10259 return 0;
10260}
10261
10262static int appsession_refresh(struct task *t) {
10263 struct proxy *p = proxy;
10264 CHTbl *htbl;
10265 ListElmt *element, *last;
10266 int i;
10267 appsess *asession;
10268 void *data;
10269
10270 while (p) {
10271 if (p->appsession_name != NULL) {
10272 htbl = &p->htbl_proxy;
10273 /* if we ever give up the use of TBLSIZ, we need to change this */
10274 for (i = 0; i < TBLSIZ; i++) {
10275 last = NULL;
10276 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
10277 asession = (appsess *)list_data(element);
10278 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
10279 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
10280 int len;
10281 /*
10282 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
10283 */
10284 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
10285 asession->sessid, asession->serverid?asession->serverid:"(null)");
10286 write(1, trash, len);
10287 }
10288 /* delete the expired element from within the hash table */
10289 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
10290 && (htbl->table[i].destroy != NULL)) {
10291 htbl->table[i].destroy(data);
10292 }
10293 if (last == NULL) {/* patient lost his head, get a new one */
10294 element = list_head(&htbl->table[i]);
10295 if (element == NULL) break; /* no heads left, go to next patient */
10296 }
10297 else
10298 element = last;
10299 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
10300 else
10301 last = element;
10302 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
10303 }
10304 }
10305 p = p->next;
10306 }
10307 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
10308 return TBLCHKINT;
10309} /* end appsession_refresh */
10310
willy tarreau18a957c2006-04-12 19:26:23 +020010311
10312/*
10313 * Local variables:
10314 * c-indent-level: 4
10315 * c-basic-offset: 4
10316 * End:
10317 */