blob: 5e08965d01aa54a26ec5a9fe7658d5d1d77fbcc5 [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 tarreaue3b30652006-05-21 16:23:22 +0200591 unsigned failed_conns, failed_resp; /* failed connect() and responses */
592 unsigned failed_secu; /* blocked responses because of security concerns */
willy tarreau535ae7a2005-12-17 12:58:00 +0100593 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100594};
595
willy tarreau5cbea6f2005-12-17 12:48:26 +0100596/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100597struct task {
598 struct task *next, *prev; /* chaining ... */
599 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100600 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100601 int state; /* task state : IDLE or RUNNING */
602 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100603 int (*process)(struct task *t); /* the function which processes the task */
604 void *context; /* the task's context */
605};
606
607/* WARNING: if new fields are added, they must be initialized in event_accept() */
608struct session {
609 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100610 /* application specific below */
611 struct timeval crexpire; /* expiration date for a client read */
612 struct timeval cwexpire; /* expiration date for a client write */
613 struct timeval srexpire; /* expiration date for a server read */
614 struct timeval swexpire; /* expiration date for a server write */
615 struct timeval cnexpire; /* expiration date for a connect */
616 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
617 struct proxy *proxy; /* the proxy this socket belongs to */
618 int cli_fd; /* the client side fd */
619 int srv_fd; /* the server side fd */
620 int cli_state; /* state of the client side */
621 int srv_state; /* state of the server side */
622 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100623 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100624 struct buffer *req; /* request buffer */
625 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100626 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100627 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100628 struct server *srv; /* the server being used */
willy tarreau18a957c2006-04-12 19:26:23 +0200629 struct pendconn *pend_pos; /* if not NULL, points to the position in the pending queue */
willy tarreau4302f492005-12-18 01:00:37 +0100630 char **req_cap; /* array of captured request headers (may be NULL) */
631 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreau9e138862006-05-14 23:06:28 +0200632 struct chunk req_line; /* points to first line */
633 struct chunk auth_hdr; /* points to 'Authorization:' header */
willy tarreaua1598082005-12-17 13:08:06 +0100634 struct {
635 int logwait; /* log fields waiting to be collected : LW_* */
636 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
637 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
willy tarreauf32f5242006-05-02 22:54:52 +0200638 long t_queue; /* delay before the session gets out of the connect queue, -1 if never occurs */
willy tarreaua1598082005-12-17 13:08:06 +0100639 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
640 long t_data; /* delay before the first data byte from the server ... */
641 unsigned long t_close; /* total session duration */
willy tarreau5e69b162006-05-12 19:49:37 +0200642 unsigned long srv_queue_size; /* number of sessions waiting for a connect slot on this server at accept() time (in direct assignment) */
643 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 +0100644 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100645 char *cli_cookie; /* cookie presented by the client, in capture mode */
646 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100647 int status; /* HTTP status from the server, negative if from proxy */
648 long long bytes; /* number of bytes transferred from the server */
649 } logs;
willy tarreau1f431b52006-05-21 14:46:15 +0200650 short int data_source; /* where to get the data we generate ourselves */
651 short int data_state; /* where to get the data we generate ourselves */
willy tarreaue0331262006-05-15 03:02:46 +0200652 union {
653 struct {
654 struct proxy *px;
655 struct server *sv;
willy tarreau1f431b52006-05-21 14:46:15 +0200656 short px_st, sv_st; /* DATA_ST_INIT or DATA_ST_DATA */
willy tarreaue0331262006-05-15 03:02:46 +0200657 } stats;
658 } data_ctx;
willy tarreau2f6ba652005-12-17 13:57:42 +0100659 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100660};
661
willy tarreaua41a8b42005-12-17 14:02:24 +0100662struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100663 int fd; /* the listen socket */
664 struct sockaddr_storage addr; /* the address we listen to */
665 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100666};
willy tarreauf32f5242006-05-02 22:54:52 +0200667
willy tarreau0f7af912005-12-17 12:21:26 +0100668struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100669 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100670 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 +0100671 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100672 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200673 struct server *srv; /* known servers */
674 int srv_act, srv_bck; /* # of running servers */
675 int tot_wact, tot_wbck; /* total weights of active and backup servers */
676 struct server **srv_map; /* the server map used to apply weights */
677 int srv_map_sz; /* the size of the effective server map */
678 int srv_rr_idx; /* next server to be elected in round robin mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100679 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100680 int cookie_len; /* strlen(cookie_name), computed only once */
681 char *appsession_name; /* name of the cookie to look for */
682 int appsession_name_len; /* strlen(appsession_name), computed only once */
683 int appsession_len; /* length of the appsession cookie value to be used */
684 int appsession_timeout;
685 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100686 char *capture_name; /* beginning of the name of the cookie to capture */
687 int capture_namelen; /* length of the cookie name to match */
688 int capture_len; /* length of the string to be captured */
willy tarreau9e138862006-05-14 23:06:28 +0200689 struct uri_auth *uri_auth; /* if non-NULL, the (list of) per-URI authentications */
willy tarreau0f7af912005-12-17 12:21:26 +0100690 int clitimeout; /* client I/O timeout (in milliseconds) */
691 int srvtimeout; /* server I/O timeout (in milliseconds) */
692 int contimeout; /* connect timeout (in milliseconds) */
693 char *id; /* proxy id */
willy tarreaudfece232006-05-02 00:19:57 +0200694 struct list pendconns; /* pending connections with no server assigned yet */
willy tarreaucb406512006-05-18 00:52:35 +0200695 int nbpend, nbpend_max; /* number of pending connections with no server assigned yet */
willy tarreauf32f5242006-05-02 22:54:52 +0200696 int totpend; /* total number of pending connections on this instance (for stats) */
willy tarreaucb406512006-05-18 00:52:35 +0200697 int nbconn, nbconn_max; /* # of active sessions */
willy tarreau14b4d432006-04-07 18:23:29 +0200698 unsigned int cum_conn; /* cumulated number of processed sessions */
willy tarreau0f7af912005-12-17 12:21:26 +0100699 int maxconn; /* max # of active sessions */
willy tarreaue3b30652006-05-21 16:23:22 +0200700 unsigned failed_conns, failed_resp; /* failed connect() and responses */
701 unsigned failed_secu; /* blocked responses because of security concerns */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100702 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100703 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100704 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100705 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100706 struct proxy *next;
707 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100708 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100709 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100710 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100711 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100712 int nb_reqadd, nb_rspadd;
713 struct hdr_exp *req_exp; /* regular expressions for request headers */
714 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100715 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
716 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
717 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
718 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100719 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100720 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100721 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
722 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100723 struct {
724 char *msg400; /* message for error 400 */
725 int len400; /* message length for error 400 */
726 char *msg403; /* message for error 403 */
727 int len403; /* message length for error 403 */
728 char *msg408; /* message for error 408 */
729 int len408; /* message length for error 408 */
730 char *msg500; /* message for error 500 */
731 int len500; /* message length for error 500 */
732 char *msg502; /* message for error 502 */
733 int len502; /* message length for error 502 */
734 char *msg503; /* message for error 503 */
735 int len503; /* message length for error 503 */
736 char *msg504; /* message for error 504 */
737 int len504; /* message length for error 504 */
738 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100739};
740
741/* info about one given fd */
742struct fdtab {
743 int (*read)(int fd); /* read function */
744 int (*write)(int fd); /* write function */
745 struct task *owner; /* the session (or proxy) associated with this fd */
746 int state; /* the state of this fd */
747};
748
749/*********************************************************************/
750
willy tarreaub952e1d2005-12-18 01:31:20 +0100751int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100752int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100753char *cfg_cfgfile = NULL; /* configuration file */
754char *progname = NULL; /* program name */
755int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100756
757/* global options */
758static struct {
759 int uid;
760 int gid;
761 int nbproc;
762 int maxconn;
763 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100764 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100765 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100766 int mode;
767 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100768 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100769 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100770 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100771 struct sockaddr_in logsrv1, logsrv2;
772} global = {
773 logfac1 : -1,
774 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100775 loglev1 : 7, /* max syslog level : debug */
776 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100777 /* others NULL OK */
778};
779
willy tarreau0f7af912005-12-17 12:21:26 +0100780/*********************************************************************/
781
willy tarreau1c2ad212005-12-18 01:11:29 +0100782fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100783 *StaticWriteEvent;
784
willy tarreau64a3cc32005-12-18 01:13:11 +0100785int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100786
willy tarreau0f7af912005-12-17 12:21:26 +0100787void **pool_session = NULL,
willy tarreau18a957c2006-04-12 19:26:23 +0200788 **pool_pendconn = NULL,
willy tarreau0f7af912005-12-17 12:21:26 +0100789 **pool_buffer = NULL,
790 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100791 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100792 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100793 **pool_capture = NULL,
794 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100795
796struct proxy *proxy = NULL; /* list of all existing proxies */
797struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100798struct task *rq = NULL; /* global run queue */
willy tarreau5e698ef2006-05-02 14:51:00 +0200799struct task wait_queue[2] = { /* global wait queue */
800 {
801 prev:LIST_HEAD(wait_queue[0]), /* expirable tasks */
802 next:LIST_HEAD(wait_queue[0]),
803 },
804 {
805 prev:LIST_HEAD(wait_queue[1]), /* non-expirable tasks */
806 next:LIST_HEAD(wait_queue[1]),
807 },
willy tarreau5cbea6f2005-12-17 12:48:26 +0100808};
willy tarreau0f7af912005-12-17 12:21:26 +0100809
willy tarreau0f7af912005-12-17 12:21:26 +0100810static int totalconn = 0; /* total # of terminated sessions */
811static int actconn = 0; /* # of active sessions */
812static int maxfd = 0; /* # of the highest fd + 1 */
813static int listeners = 0; /* # of listeners */
814static int stopping = 0; /* non zero means stopping in progress */
815static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaue0331262006-05-15 03:02:46 +0200816static struct timeval start_date; /* the process's start date */
willy tarreaua41a8b42005-12-17 14:02:24 +0100817static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100818
willy tarreau53e99702006-03-25 18:53:50 +0100819/* Here we store informations about the pids of the processes we may pause
820 * or kill. We will send them a signal every 10 ms until we can bind to all
821 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100822 */
willy tarreau53e99702006-03-25 18:53:50 +0100823#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100824static int nb_oldpids = 0;
825static int *oldpids = NULL;
826static int oldpids_sig; /* use USR1 or TERM */
827
willy tarreau08dedbe2005-12-18 01:13:48 +0100828#if defined(ENABLE_EPOLL)
829/* FIXME: this is dirty, but at the moment, there's no other solution to remove
830 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
831 * structure with pointers to functions such as init_fd() and close_fd(), plus
832 * a private structure with several pointers to places such as below.
833 */
834
835static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
836#endif
837
willy tarreau0f7af912005-12-17 12:21:26 +0100838static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100839/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100840static char trash[BUFSIZE];
841
willy tarreaudd07e972005-12-18 00:48:48 +0100842const int zero = 0;
843const int one = 1;
844
willy tarreau0f7af912005-12-17 12:21:26 +0100845/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100846 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100847 */
848
849#define MAX_SYSLOG_LEN 1024
850#define NB_LOG_FACILITIES 24
851const char *log_facilities[NB_LOG_FACILITIES] = {
852 "kern", "user", "mail", "daemon",
853 "auth", "syslog", "lpr", "news",
854 "uucp", "cron", "auth2", "ftp",
855 "ntp", "audit", "alert", "cron2",
856 "local0", "local1", "local2", "local3",
857 "local4", "local5", "local6", "local7"
858};
859
860
861#define NB_LOG_LEVELS 8
862const char *log_levels[NB_LOG_LEVELS] = {
863 "emerg", "alert", "crit", "err",
864 "warning", "notice", "info", "debug"
865};
866
867#define SYSLOG_PORT 514
868
869const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
870 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100871
willy tarreaub1285d52005-12-18 01:20:14 +0100872const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau078c79a2006-05-13 12:23:58 +0200873const char sess_fin_state[8] = "-RCHDLQ7"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, unknown */
willy tarreau036e1ce2005-12-17 13:46:33 +0100874const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
875const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
876 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
877 unknown, Set-cookie Rewritten */
878
willy tarreau0f7af912005-12-17 12:21:26 +0100879#define MAX_HOSTNAME_LEN 32
880static char hostname[MAX_HOSTNAME_LEN] = "";
881
willy tarreau8337c6b2005-12-17 13:41:01 +0100882const char *HTTP_302 =
883 "HTTP/1.0 302 Found\r\n"
884 "Cache-Control: no-cache\r\n"
885 "Connection: close\r\n"
886 "Location: "; /* not terminated since it will be concatenated with the URL */
887
willy tarreauc1f47532005-12-18 01:08:26 +0100888/* same as 302 except that the browser MUST retry with the GET method */
889const char *HTTP_303 =
890 "HTTP/1.0 303 See Other\r\n"
891 "Cache-Control: no-cache\r\n"
892 "Connection: close\r\n"
893 "Location: "; /* not terminated since it will be concatenated with the URL */
894
willy tarreaua1598082005-12-17 13:08:06 +0100895const char *HTTP_400 =
896 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100897 "Cache-Control: no-cache\r\n"
898 "Connection: close\r\n"
899 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100900 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100901
willy tarreau9e138862006-05-14 23:06:28 +0200902/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
903const char *HTTP_401_fmt =
904 "HTTP/1.0 401 Unauthorized\r\n"
905 "Cache-Control: no-cache\r\n"
906 "Connection: close\r\n"
907 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
908 "\r\n"
909 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
910
willy tarreaua1598082005-12-17 13:08:06 +0100911const char *HTTP_403 =
912 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100913 "Cache-Control: no-cache\r\n"
914 "Connection: close\r\n"
915 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100916 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
917
willy tarreau8337c6b2005-12-17 13:41:01 +0100918const char *HTTP_408 =
919 "HTTP/1.0 408 Request Time-out\r\n"
920 "Cache-Control: no-cache\r\n"
921 "Connection: close\r\n"
922 "\r\n"
923 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
924
willy tarreau750a4722005-12-17 13:21:24 +0100925const char *HTTP_500 =
926 "HTTP/1.0 500 Server Error\r\n"
927 "Cache-Control: no-cache\r\n"
928 "Connection: close\r\n"
929 "\r\n"
930 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100931
932const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100933 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100934 "Cache-Control: no-cache\r\n"
935 "Connection: close\r\n"
936 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100937 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
938
939const char *HTTP_503 =
940 "HTTP/1.0 503 Service Unavailable\r\n"
941 "Cache-Control: no-cache\r\n"
942 "Connection: close\r\n"
943 "\r\n"
944 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
945
946const char *HTTP_504 =
947 "HTTP/1.0 504 Gateway Time-out\r\n"
948 "Cache-Control: no-cache\r\n"
949 "Connection: close\r\n"
950 "\r\n"
951 "<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 +0100952
willy tarreau0f7af912005-12-17 12:21:26 +0100953/*********************************************************************/
954/* statistics ******************************************************/
955/*********************************************************************/
956
willy tarreau750a4722005-12-17 13:21:24 +0100957#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100958static int stats_tsk_lsrch, stats_tsk_rsrch,
959 stats_tsk_good, stats_tsk_right, stats_tsk_left,
960 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100961#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100962
963
964/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100965/* debugging *******************************************************/
966/*********************************************************************/
967#ifdef DEBUG_FULL
968static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau3504a012006-05-14 23:20:07 +0200969static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau750a4722005-12-17 13:21:24 +0100970#endif
971
972/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100973/* function prototypes *********************************************/
974/*********************************************************************/
975
976int event_accept(int fd);
977int event_cli_read(int fd);
978int event_cli_write(int fd);
979int event_srv_read(int fd);
980int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100981int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100982
willy tarreau12350152005-12-18 01:03:27 +0100983static int appsession_task_init(void);
984static int appsession_init(void);
985static int appsession_refresh(struct task *t);
986
willy tarreau0f7af912005-12-17 12:21:26 +0100987/*********************************************************************/
988/* general purpose functions ***************************************/
989/*********************************************************************/
990
991void display_version() {
992 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100993 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100994}
995
996/*
997 * This function prints the command line usage and exits
998 */
999void usage(char *name) {
1000 display_version();
1001 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +01001002 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +01001003#if STATTIME > 0
1004 "sl"
1005#endif
willy tarreau746e26b2006-03-25 11:14:35 +01001006 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
1007 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +01001008 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +01001009 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +01001010 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +01001011#if STATTIME > 0
1012 " -s enables statistics output\n"
1013 " -l enables long statistics format\n"
1014#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001015 " -D goes daemon ; implies -q\n"
1016 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +01001017 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +01001018 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +01001019 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +01001020 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +01001021 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001022#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01001023 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001024#endif
1025#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01001026 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001027#endif
willy tarreau53e99702006-03-25 18:53:50 +01001028 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +01001029 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01001030 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +01001031 exit(1);
1032}
1033
1034
1035/*
willy tarreaud0fb4652005-12-18 01:32:04 +01001036 * Displays the message on stderr with the date and pid. Overrides the quiet
1037 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +01001038 */
1039void Alert(char *fmt, ...) {
1040 va_list argp;
1041 struct timeval tv;
1042 struct tm *tm;
1043
willy tarreaud0fb4652005-12-18 01:32:04 +01001044 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001045 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +01001046
willy tarreau5cbea6f2005-12-17 12:48:26 +01001047 gettimeofday(&tv, NULL);
1048 tm=localtime(&tv.tv_sec);
1049 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001050 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001051 vfprintf(stderr, fmt, argp);
1052 fflush(stderr);
1053 va_end(argp);
1054 }
willy tarreau0f7af912005-12-17 12:21:26 +01001055}
1056
1057
1058/*
1059 * Displays the message on stderr with the date and pid.
1060 */
1061void Warning(char *fmt, ...) {
1062 va_list argp;
1063 struct timeval tv;
1064 struct tm *tm;
1065
willy tarreau982249e2005-12-18 00:57:06 +01001066 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001067 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +01001068
willy tarreau5cbea6f2005-12-17 12:48:26 +01001069 gettimeofday(&tv, NULL);
1070 tm=localtime(&tv.tv_sec);
1071 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001072 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001073 vfprintf(stderr, fmt, argp);
1074 fflush(stderr);
1075 va_end(argp);
1076 }
1077}
1078
1079/*
1080 * Displays the message on <out> only if quiet mode is not set.
1081 */
1082void qfprintf(FILE *out, char *fmt, ...) {
1083 va_list argp;
1084
willy tarreau982249e2005-12-18 00:57:06 +01001085 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001086 va_start(argp, fmt);
1087 vfprintf(out, fmt, argp);
1088 fflush(out);
1089 va_end(argp);
1090 }
willy tarreau0f7af912005-12-17 12:21:26 +01001091}
1092
1093
1094/*
1095 * converts <str> to a struct sockaddr_in* which is locally allocated.
1096 * The format is "addr:port", where "addr" can be empty or "*" to indicate
1097 * INADDR_ANY.
1098 */
1099struct sockaddr_in *str2sa(char *str) {
1100 static struct sockaddr_in sa;
1101 char *c;
1102 int port;
1103
willy tarreaua1598082005-12-17 13:08:06 +01001104 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +01001105 str=strdup(str);
1106
1107 if ((c=strrchr(str,':')) != NULL) {
1108 *c++=0;
1109 port=atol(c);
1110 }
1111 else
1112 port=0;
1113
1114 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1115 sa.sin_addr.s_addr = INADDR_ANY;
1116 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01001117 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001118 struct hostent *he;
1119
1120 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001121 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001122 }
1123 else
1124 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1125 }
1126 sa.sin_port=htons(port);
1127 sa.sin_family=AF_INET;
1128
1129 free(str);
1130 return &sa;
1131}
1132
willy tarreaub1285d52005-12-18 01:20:14 +01001133/*
1134 * converts <str> to a two struct in_addr* which are locally allocated.
1135 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1136 * is optionnal and either in the dotted or CIDR notation.
1137 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1138 */
1139int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1140 char *c;
1141 unsigned long len;
1142
1143 memset(mask, 0, sizeof(*mask));
1144 memset(addr, 0, sizeof(*addr));
1145 str=strdup(str);
1146
1147 if ((c = strrchr(str, '/')) != NULL) {
1148 *c++ = 0;
1149 /* c points to the mask */
1150 if (strchr(c, '.') != NULL) { /* dotted notation */
1151 if (!inet_pton(AF_INET, c, mask))
1152 return 0;
1153 }
1154 else { /* mask length */
1155 char *err;
1156 len = strtol(c, &err, 10);
1157 if (!*c || (err && *err) || (unsigned)len > 32)
1158 return 0;
1159 if (len)
1160 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1161 else
1162 mask->s_addr = 0;
1163 }
1164 }
1165 else {
1166 mask->s_addr = 0xFFFFFFFF;
1167 }
1168 if (!inet_pton(AF_INET, str, addr)) {
1169 struct hostent *he;
1170
1171 if ((he = gethostbyname(str)) == NULL) {
1172 return 0;
1173 }
1174 else
1175 *addr = *(struct in_addr *) *(he->h_addr_list);
1176 }
1177 free(str);
1178 return 1;
1179}
1180
willy tarreau9fe663a2005-12-17 13:02:59 +01001181
1182/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001183 * converts <str> to a list of listeners which are dynamically allocated.
1184 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1185 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1186 * - <port> is a numerical port from 1 to 65535 ;
1187 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1188 * This can be repeated as many times as necessary, separated by a coma.
1189 * The <tail> argument is a pointer to a current list which should be appended
1190 * to the tail of the new list. The pointer to the new list is returned.
1191 */
1192struct listener *str2listener(char *str, struct listener *tail) {
1193 struct listener *l;
1194 char *c, *next, *range, *dupstr;
1195 int port, end;
1196
1197 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001198
willy tarreaua41a8b42005-12-17 14:02:24 +01001199 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001200 struct sockaddr_storage ss;
1201
willy tarreaua41a8b42005-12-17 14:02:24 +01001202 str = next;
1203 /* 1) look for the end of the first address */
1204 if ((next = strrchr(str, ',')) != NULL) {
1205 *next++ = 0;
1206 }
1207
willy tarreau8a86dbf2005-12-18 00:45:59 +01001208 /* 2) look for the addr/port delimiter, it's the last colon. */
1209 if ((range = strrchr(str, ':')) == NULL) {
1210 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001211 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001212 }
1213
1214 *range++ = 0;
1215
1216 if (strrchr(str, ':') != NULL) {
1217 /* IPv6 address contains ':' */
1218 memset(&ss, 0, sizeof(ss));
1219 ss.ss_family = AF_INET6;
1220
1221 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1222 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001223 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001224 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001225 }
1226 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001227 memset(&ss, 0, sizeof(ss));
1228 ss.ss_family = AF_INET;
1229
1230 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1231 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1232 }
1233 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1234 struct hostent *he;
1235
1236 if ((he = gethostbyname(str)) == NULL) {
1237 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001238 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001239 }
1240 else
1241 ((struct sockaddr_in *)&ss)->sin_addr =
1242 *(struct in_addr *) *(he->h_addr_list);
1243 }
1244 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001245
1246 /* 3) look for the port-end delimiter */
1247 if ((c = strchr(range, '-')) != NULL) {
1248 *c++ = 0;
1249 end = atol(c);
1250 }
1251 else {
1252 end = atol(range);
1253 }
1254
willy tarreaud0fb4652005-12-18 01:32:04 +01001255 port = atol(range);
1256
1257 if (port < 1 || port > 65535) {
1258 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1259 goto fail;
1260 }
1261
1262 if (end < 1 || end > 65535) {
1263 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1264 goto fail;
1265 }
1266
1267 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001268 l = (struct listener *)calloc(1, sizeof(struct listener));
1269 l->next = tail;
1270 tail = l;
1271
willy tarreau41310e72006-03-25 18:17:56 +01001272 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001273 l->addr = ss;
1274 if (ss.ss_family == AF_INET6)
1275 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1276 else
1277 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1278
willy tarreaua41a8b42005-12-17 14:02:24 +01001279 } /* end for(port) */
1280 } /* end while(next) */
1281 free(dupstr);
1282 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001283 fail:
1284 free(dupstr);
1285 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001286}
1287
willy tarreau4302f492005-12-18 01:00:37 +01001288
1289#define FD_SETS_ARE_BITFIELDS
1290#ifdef FD_SETS_ARE_BITFIELDS
1291/*
1292 * This map is used with all the FD_* macros to check whether a particular bit
1293 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1294 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1295 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1296 * exclusively to the macros.
1297 */
1298fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1299fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1300
1301#else
1302#error "Check if your OS uses bitfields for fd_sets"
1303#endif
1304
1305/* will try to encode the string <string> replacing all characters tagged in
1306 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1307 * prefixed by <escape>, and will store the result between <start> (included
1308 *) and <stop> (excluded), and will always terminate the string with a '\0'
1309 * before <stop>. The position of the '\0' is returned if the conversion
1310 * completes. If bytes are missing between <start> and <stop>, then the
1311 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1312 * cannot even be stored so we return <start> without writing the 0.
1313 * The input string must also be zero-terminated.
1314 */
1315char hextab[16] = "0123456789ABCDEF";
1316char *encode_string(char *start, char *stop,
1317 const char escape, const fd_set *map,
1318 const char *string)
1319{
1320 if (start < stop) {
1321 stop--; /* reserve one byte for the final '\0' */
1322 while (start < stop && *string != 0) {
1323 if (!FD_ISSET((unsigned char)(*string), map))
1324 *start++ = *string;
1325 else {
1326 if (start + 3 >= stop)
1327 break;
1328 *start++ = escape;
1329 *start++ = hextab[(*string >> 4) & 15];
1330 *start++ = hextab[*string & 15];
1331 }
1332 string++;
1333 }
1334 *start = '\0';
1335 }
1336 return start;
1337}
willy tarreaua41a8b42005-12-17 14:02:24 +01001338
1339/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001340 * This function sends a syslog message to both log servers of a proxy,
1341 * or to global log servers if the proxy is NULL.
1342 * It also tries not to waste too much time computing the message header.
1343 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001344 */
1345void send_log(struct proxy *p, int level, char *message, ...) {
1346 static int logfd = -1; /* syslog UDP socket */
1347 static long tvsec = -1; /* to force the string to be initialized */
1348 struct timeval tv;
1349 va_list argp;
1350 static char logmsg[MAX_SYSLOG_LEN];
1351 static char *dataptr = NULL;
1352 int fac_level;
1353 int hdr_len, data_len;
1354 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001355 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001356 int nbloggers = 0;
1357 char *log_ptr;
1358
1359 if (logfd < 0) {
1360 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1361 return;
1362 }
1363
1364 if (level < 0 || progname == NULL || message == NULL)
1365 return;
1366
1367 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001368 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001369 /* this string is rebuild only once a second */
1370 struct tm *tm = localtime(&tv.tv_sec);
1371 tvsec = tv.tv_sec;
1372
willy tarreauc29948c2005-12-17 13:10:27 +01001373 hdr_len = snprintf(logmsg, sizeof(logmsg),
1374 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1375 monthname[tm->tm_mon],
1376 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1377 progname, pid);
1378 /* WARNING: depending upon implementations, snprintf may return
1379 * either -1 or the number of bytes that would be needed to store
1380 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001381 */
willy tarreauc29948c2005-12-17 13:10:27 +01001382 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1383 hdr_len = sizeof(logmsg);
1384
1385 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001386 }
1387
1388 va_start(argp, message);
1389 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001390 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1391 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001392 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001393 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001394
1395 if (p == NULL) {
1396 if (global.logfac1 >= 0) {
1397 sa[nbloggers] = &global.logsrv1;
1398 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001399 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001400 nbloggers++;
1401 }
1402 if (global.logfac2 >= 0) {
1403 sa[nbloggers] = &global.logsrv2;
1404 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001405 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001406 nbloggers++;
1407 }
1408 } else {
1409 if (p->logfac1 >= 0) {
1410 sa[nbloggers] = &p->logsrv1;
1411 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001412 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001413 nbloggers++;
1414 }
1415 if (p->logfac2 >= 0) {
1416 sa[nbloggers] = &p->logsrv2;
1417 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001418 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001419 nbloggers++;
1420 }
1421 }
1422
1423 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001424 /* we can filter the level of the messages that are sent to each logger */
1425 if (level > loglevel[nbloggers])
1426 continue;
1427
willy tarreauc29948c2005-12-17 13:10:27 +01001428 /* For each target, we may have a different facility.
1429 * We can also have a different log level for each message.
1430 * This induces variations in the message header length.
1431 * Since we don't want to recompute it each time, nor copy it every
1432 * time, we only change the facility in the pre-computed header,
1433 * and we change the pointer to the header accordingly.
1434 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001435 fac_level = (facilities[nbloggers] << 3) + level;
1436 log_ptr = logmsg + 3; /* last digit of the log level */
1437 do {
1438 *log_ptr = '0' + fac_level % 10;
1439 fac_level /= 10;
1440 log_ptr--;
1441 } while (fac_level && log_ptr > logmsg);
1442 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001443
willy tarreauc29948c2005-12-17 13:10:27 +01001444 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001445
1446#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001447 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001448 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1449#else
willy tarreauc29948c2005-12-17 13:10:27 +01001450 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001451 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1452#endif
1453 }
willy tarreau0f7af912005-12-17 12:21:26 +01001454}
1455
1456
1457/* sets <tv> to the current time */
1458static inline struct timeval *tv_now(struct timeval *tv) {
1459 if (tv)
1460 gettimeofday(tv, NULL);
1461 return tv;
1462}
1463
1464/*
1465 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1466 */
willy tarreaudab722b2006-05-04 19:23:38 +02001467static struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
willy tarreau0f7af912005-12-17 12:21:26 +01001468 if (!tv || !from)
1469 return NULL;
1470 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1471 tv->tv_sec = from->tv_sec + (ms/1000);
1472 while (tv->tv_usec >= 1000000) {
1473 tv->tv_usec -= 1000000;
1474 tv->tv_sec++;
1475 }
1476 return tv;
1477}
1478
1479/*
1480 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001481 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001482 */
1483static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001484 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001485 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001486 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001487 return 1;
1488 else if (tv1->tv_usec < tv2->tv_usec)
1489 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001490 else if (tv1->tv_usec > tv2->tv_usec)
1491 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001492 else
1493 return 0;
1494}
1495
1496/*
1497 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001498 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001499 */
1500unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1501 int cmp;
1502 unsigned long ret;
1503
1504
willy tarreauef900ab2005-12-17 12:52:52 +01001505 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001506 if (!cmp)
1507 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001508 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001509 struct timeval *tmp = tv1;
1510 tv1 = tv2;
1511 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001512 }
willy tarreauef900ab2005-12-17 12:52:52 +01001513 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001514 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001515 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001516 else
willy tarreauef900ab2005-12-17 12:52:52 +01001517 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001518 return (unsigned long) ret;
1519}
1520
1521/*
willy tarreau750a4722005-12-17 13:21:24 +01001522 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001523 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001524 */
1525static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1526 unsigned long ret;
1527
willy tarreau6e682ce2005-12-17 13:26:49 +01001528 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1529 if (tv2->tv_usec > tv1->tv_usec)
1530 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001531 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001532 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001533 return (unsigned long) ret;
1534}
1535
1536/*
willy tarreau0f7af912005-12-17 12:21:26 +01001537 * 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 +01001538 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001539 */
willy tarreaudab722b2006-05-04 19:23:38 +02001540static int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001541 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001542 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001543 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001544 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001545 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001546 else
1547 return 0;
1548 }
willy tarreau0f7af912005-12-17 12:21:26 +01001549 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001550 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001551 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001552 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001553 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001554 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001555 else
1556 return 0;
1557}
1558
1559/*
1560 * returns the remaining time between tv1=now and event=tv2
1561 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001562 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001563 */
1564static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1565 unsigned long ret;
1566
willy tarreau0f7af912005-12-17 12:21:26 +01001567 if (tv_cmp_ms(tv1, tv2) >= 0)
1568 return 0; /* event elapsed */
1569
willy tarreauef900ab2005-12-17 12:52:52 +01001570 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001571 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001572 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001573 else
willy tarreauef900ab2005-12-17 12:52:52 +01001574 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001575 return (unsigned long) ret;
1576}
1577
1578
1579/*
1580 * zeroes a struct timeval
1581 */
1582
1583static inline struct timeval *tv_eternity(struct timeval *tv) {
1584 tv->tv_sec = tv->tv_usec = 0;
1585 return tv;
1586}
1587
1588/*
1589 * returns 1 if tv is null, else 0
1590 */
1591static inline int tv_iseternity(struct timeval *tv) {
1592 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1593 return 1;
1594 else
1595 return 0;
1596}
1597
1598/*
1599 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1600 * considering that 0 is the eternity.
1601 */
willy tarreaudab722b2006-05-04 19:23:38 +02001602static int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001603 if (tv_iseternity(tv1))
1604 if (tv_iseternity(tv2))
1605 return 0; /* same */
1606 else
1607 return 1; /* tv1 later than tv2 */
1608 else if (tv_iseternity(tv2))
1609 return -1; /* tv2 later than tv1 */
1610
1611 if (tv1->tv_sec > tv2->tv_sec)
1612 return 1;
1613 else if (tv1->tv_sec < tv2->tv_sec)
1614 return -1;
1615 else if (tv1->tv_usec > tv2->tv_usec)
1616 return 1;
1617 else if (tv1->tv_usec < tv2->tv_usec)
1618 return -1;
1619 else
1620 return 0;
1621}
1622
1623/*
1624 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1625 * considering that 0 is the eternity.
1626 */
willy tarreaudab722b2006-05-04 19:23:38 +02001627static int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001628 if (tv_iseternity(tv1))
1629 if (tv_iseternity(tv2))
1630 return 0; /* same */
1631 else
1632 return 1; /* tv1 later than tv2 */
1633 else if (tv_iseternity(tv2))
1634 return -1; /* tv2 later than tv1 */
1635
willy tarreauefae1842005-12-17 12:51:03 +01001636 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001637 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001638 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001639 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001640 return -1;
1641 else
1642 return 0;
1643 }
1644 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001645 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001646 return 1;
1647 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001648 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001649 return -1;
1650 else
1651 return 0;
1652}
1653
1654/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001655 * returns the remaining time between tv1=now and event=tv2
1656 * if tv2 is passed, 0 is returned.
1657 * Returns TIME_ETERNITY if tv2 is eternity.
1658 */
willy tarreaudab722b2006-05-04 19:23:38 +02001659static unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001660 unsigned long ret;
1661
1662 if (tv_iseternity(tv2))
1663 return TIME_ETERNITY;
1664
1665 if (tv_cmp_ms(tv1, tv2) >= 0)
1666 return 0; /* event elapsed */
1667
1668 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1669 if (tv2->tv_usec > tv1->tv_usec)
1670 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1671 else
1672 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1673 return (unsigned long) ret;
1674}
1675
1676/*
willy tarreau0f7af912005-12-17 12:21:26 +01001677 * returns the first event between tv1 and tv2 into tvmin.
1678 * a zero tv is ignored. tvmin is returned.
1679 */
1680static inline struct timeval *tv_min(struct timeval *tvmin,
1681 struct timeval *tv1, struct timeval *tv2) {
1682
1683 if (tv_cmp2(tv1, tv2) <= 0)
1684 *tvmin = *tv1;
1685 else
1686 *tvmin = *tv2;
1687
1688 return tvmin;
1689}
1690
1691
1692
1693/***********************************************************/
1694/* fd management ***************************************/
1695/***********************************************************/
1696
1697
1698
willy tarreau5cbea6f2005-12-17 12:48:26 +01001699/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1700 * The file descriptor is also closed.
1701 */
willy tarreaudab722b2006-05-04 19:23:38 +02001702static void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001703 FD_CLR(fd, StaticReadEvent);
1704 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001705#if defined(ENABLE_EPOLL)
1706 if (PrevReadEvent) {
1707 FD_CLR(fd, PrevReadEvent);
1708 FD_CLR(fd, PrevWriteEvent);
1709 }
1710#endif
1711
willy tarreau5cbea6f2005-12-17 12:48:26 +01001712 close(fd);
1713 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001714
1715 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1716 maxfd--;
1717}
1718
1719/* recomputes the maxfd limit from the fd */
1720static inline void fd_insert(int fd) {
1721 if (fd+1 > maxfd)
1722 maxfd = fd+1;
1723}
1724
1725/*************************************************************/
1726/* task management ***************************************/
1727/*************************************************************/
1728
willy tarreau5cbea6f2005-12-17 12:48:26 +01001729/* puts the task <t> in run queue <q>, and returns <t> */
1730static inline struct task *task_wakeup(struct task **q, struct task *t) {
1731 if (t->state == TASK_RUNNING)
1732 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001733 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001734 t->rqnext = *q;
1735 t->state = TASK_RUNNING;
1736 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001737 }
1738}
1739
willy tarreau5cbea6f2005-12-17 12:48:26 +01001740/* removes the task <t> from the queue <q>
1741 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001742 * set the run queue to point to the next one, and return it
1743 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001744static inline struct task *task_sleep(struct task **q, struct task *t) {
1745 if (t->state == TASK_RUNNING) {
1746 *q = t->rqnext;
1747 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001748 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001749 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001750}
1751
1752/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001753 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001754 * from the run queue. A pointer to the task itself is returned.
1755 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001756static inline struct task *task_delete(struct task *t) {
1757 t->prev->next = t->next;
1758 t->next->prev = t->prev;
1759 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001760}
1761
1762/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001763 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001764 */
1765static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001766 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001767}
1768
willy tarreau5cbea6f2005-12-17 12:48:26 +01001769/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001770 * may be only moved or left where it was, depending on its timing requirements.
1771 * <task> is returned.
1772 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001773struct task *task_queue(struct task *task) {
1774 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001775 struct task *start_from;
1776
willy tarreau5e698ef2006-05-02 14:51:00 +02001777 /* This is a very dirty hack to queue non-expirable tasks in another queue
1778 * in order to avoid pulluting the tail of the standard queue. This will go
1779 * away with the new O(log(n)) scheduler anyway.
1780 */
1781 if (tv_iseternity(&task->expire)) {
1782 /* if the task was queued in the standard wait queue, we must dequeue it */
1783 if (task->prev) {
1784 if (task->wq == LIST_HEAD(wait_queue[1]))
1785 return task;
1786 else {
1787 task_delete(task);
1788 task->prev = NULL;
1789 }
1790 }
1791 list = task->wq = LIST_HEAD(wait_queue[1]);
1792 } else {
1793 /* if the task was queued in the eternity queue, we must dequeue it */
1794 if (task->prev && (task->wq == LIST_HEAD(wait_queue[1]))) {
1795 task_delete(task);
1796 task->prev = NULL;
1797 list = task->wq = LIST_HEAD(wait_queue[0]);
1798 }
1799 }
1800
1801 /* next, test if the task was already in a list */
willy tarreau0f7af912005-12-17 12:21:26 +01001802 if (task->prev == NULL) {
1803 // start_from = list;
1804 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001805#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001806 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001807#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001808 /* insert the unlinked <task> into the list, searching back from the last entry */
1809 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1810 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001811#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001812 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001813#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001814 }
1815
1816 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1817 // start_from = start_from->next;
1818 // stats_tsk_nsrch++;
1819 // }
1820 }
1821 else if (task->prev == list ||
1822 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1823 start_from = task->next;
1824 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001825#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001826 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001827#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001828 return task; /* it's already in the right place */
1829 }
1830
willy tarreau750a4722005-12-17 13:21:24 +01001831#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001832 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001833#endif
1834
1835 /* if the task is not at the right place, there's little chance that
1836 * it has only shifted a bit, and it will nearly always be queued
1837 * at the end of the list because of constant timeouts
1838 * (observed in real case).
1839 */
1840#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1841 start_from = list->prev; /* assume we'll queue to the end of the list */
1842 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1843 start_from = start_from->prev;
1844#if STATTIME > 0
1845 stats_tsk_lsrch++;
1846#endif
1847 }
1848#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001849 /* insert the unlinked <task> into the list, searching after position <start_from> */
1850 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1851 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001852#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001853 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001854#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001855 }
willy tarreau750a4722005-12-17 13:21:24 +01001856#endif /* WE_REALLY_... */
1857
willy tarreau0f7af912005-12-17 12:21:26 +01001858 /* we need to unlink it now */
1859 task_delete(task);
1860 }
1861 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001862#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001863 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001864#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001865#ifdef LEFT_TO_TOP /* not very good */
1866 start_from = list;
1867 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1868 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001869#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001870 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001871#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001872 }
1873#else
1874 start_from = task->prev->prev; /* valid because of the previous test above */
1875 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1876 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001877#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001878 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001879#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001880 }
1881#endif
1882 /* we need to unlink it now */
1883 task_delete(task);
1884 }
1885 task->prev = start_from;
1886 task->next = start_from->next;
1887 task->next->prev = task;
1888 start_from->next = task;
1889 return task;
1890}
1891
1892
1893/*********************************************************************/
willy tarreau18a957c2006-04-12 19:26:23 +02001894/* pending connections queues **************************************/
1895/*********************************************************************/
1896
1897/*
willy tarreaudfece232006-05-02 00:19:57 +02001898 * Detaches pending connection <p>, decreases the pending count, and frees
1899 * the pending connection. The connection might have been queued to a specific
1900 * server as well as to the proxy. The session also gets marked unqueued.
willy tarreau18a957c2006-04-12 19:26:23 +02001901 */
willy tarreaudfece232006-05-02 00:19:57 +02001902static void pendconn_free(struct pendconn *p) {
1903 LIST_DEL(&p->list);
1904 p->sess->pend_pos = NULL;
1905 if (p->srv)
1906 p->srv->nbpend--;
1907 else
1908 p->sess->proxy->nbpend--;
willy tarreauf32f5242006-05-02 22:54:52 +02001909 p->sess->proxy->totpend--;
willy tarreaudfece232006-05-02 00:19:57 +02001910 pool_free(pendconn, p);
1911}
1912
1913/* Returns the first pending connection for server <s>, which may be NULL if
1914 * nothing is pending.
1915 */
1916static inline struct pendconn *pendconn_from_srv(struct server *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001917 if (!s->nbpend)
1918 return NULL;
1919
1920 return LIST_ELEM(s->pendconns.n, struct pendconn *, list);
1921}
1922
willy tarreaudfece232006-05-02 00:19:57 +02001923/* Returns the first pending connection for proxy <px>, which may be NULL if
1924 * nothing is pending.
willy tarreau18a957c2006-04-12 19:26:23 +02001925 */
willy tarreaudfece232006-05-02 00:19:57 +02001926static inline struct pendconn *pendconn_from_px(struct proxy *px) {
1927 if (!px->nbpend)
1928 return NULL;
1929
1930 return LIST_ELEM(px->pendconns.n, struct pendconn *, list);
willy tarreau18a957c2006-04-12 19:26:23 +02001931}
1932
willy tarreaubc2eda62006-05-04 15:16:23 +02001933/* Detaches the next pending connection from either a server or a proxy, and
1934 * returns its associated session. If no pending connection is found, NULL is
1935 * returned. Note that neither <srv> nor <px> can be NULL.
willy tarreau18a957c2006-04-12 19:26:23 +02001936 */
willy tarreaubc2eda62006-05-04 15:16:23 +02001937static struct session *pendconn_get_next_sess(struct server *srv, struct proxy *px) {
willy tarreau18a957c2006-04-12 19:26:23 +02001938 struct pendconn *p;
1939 struct session *sess;
1940
willy tarreaubc2eda62006-05-04 15:16:23 +02001941 p = pendconn_from_srv(srv);
willy tarreaudfece232006-05-02 00:19:57 +02001942 if (!p) {
willy tarreaubc2eda62006-05-04 15:16:23 +02001943 p = pendconn_from_px(px);
willy tarreaudfece232006-05-02 00:19:57 +02001944 if (!p)
1945 return NULL;
willy tarreaubc2eda62006-05-04 15:16:23 +02001946 p->sess->srv = srv;
willy tarreaudfece232006-05-02 00:19:57 +02001947 }
willy tarreau18a957c2006-04-12 19:26:23 +02001948 sess = p->sess;
1949 pendconn_free(p);
1950 return sess;
1951}
1952
willy tarreaudfece232006-05-02 00:19:57 +02001953/* Adds the session <sess> to the pending connection list of server <sess>->srv
1954 * or to the one of <sess>->proxy if srv is NULL. All counters and back pointers
1955 * are updated accordingly. Returns NULL if no memory is available, otherwise the
1956 * pendconn itself.
willy tarreau18a957c2006-04-12 19:26:23 +02001957 */
willy tarreaudfece232006-05-02 00:19:57 +02001958static struct pendconn *pendconn_add(struct session *sess) {
willy tarreau18a957c2006-04-12 19:26:23 +02001959 struct pendconn *p;
1960
1961 p = pool_alloc(pendconn);
1962 if (!p)
1963 return NULL;
1964
willy tarreau18a957c2006-04-12 19:26:23 +02001965 sess->pend_pos = p;
willy tarreaudfece232006-05-02 00:19:57 +02001966 p->sess = sess;
1967 p->srv = sess->srv;
1968 if (sess->srv) {
1969 LIST_ADDQ(&sess->srv->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001970 sess->logs.srv_queue_size += sess->srv->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001971 sess->srv->nbpend++;
willy tarreaucb406512006-05-18 00:52:35 +02001972 if (sess->srv->nbpend > sess->srv->nbpend_max)
1973 sess->srv->nbpend_max = sess->srv->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001974 } else {
1975 LIST_ADDQ(&sess->proxy->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001976 sess->logs.prx_queue_size += sess->proxy->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001977 sess->proxy->nbpend++;
willy tarreaucb406512006-05-18 00:52:35 +02001978 if (sess->proxy->nbpend > sess->proxy->nbpend_max)
1979 sess->proxy->nbpend_max = sess->proxy->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001980 }
willy tarreauf32f5242006-05-02 22:54:52 +02001981 sess->proxy->totpend++;
willy tarreau18a957c2006-04-12 19:26:23 +02001982 return p;
1983}
1984
willy tarreau59a6cc22006-05-12 01:29:08 +02001985/* returns 0 if nothing has to be done for server <s> regarding queued connections,
1986 * and non-zero otherwise. Suited for and if/else usage.
1987 */
1988static inline int may_dequeue_tasks(struct server *s, struct proxy *p) {
1989 return (s && (s->nbpend || p->nbpend) &&
1990 s->maxconn && s->cur_sess < s->maxconn && s->queue_mgt);
1991}
1992
1993
1994
willy tarreau18a957c2006-04-12 19:26:23 +02001995/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +01001996/* more specific functions ***************************************/
1997/*********************************************************************/
1998
1999/* some prototypes */
2000static int maintain_proxies(void);
2001
willy tarreaub952e1d2005-12-18 01:31:20 +01002002/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01002003 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
2004 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01002005static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01002006#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002007 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
2008#else
willy tarreaua1598082005-12-17 13:08:06 +01002009#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002010 return getsockname(fd, (struct sockaddr *)sa, salen);
2011#else
2012 return -1;
2013#endif
2014#endif
2015}
2016
2017/*
2018 * frees the context associated to a session. It must have been removed first.
2019 */
willy tarreaudfece232006-05-02 00:19:57 +02002020static void session_free(struct session *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02002021 if (s->pend_pos)
2022 pendconn_free(s->pend_pos);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002023 if (s->req)
2024 pool_free(buffer, s->req);
2025 if (s->rep)
2026 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01002027
2028 if (s->rsp_cap != NULL) {
2029 struct cap_hdr *h;
2030 for (h = s->proxy->rsp_cap; h; h = h->next) {
2031 if (s->rsp_cap[h->index] != NULL)
2032 pool_free_to(h->pool, s->rsp_cap[h->index]);
2033 }
2034 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
2035 }
2036 if (s->req_cap != NULL) {
2037 struct cap_hdr *h;
2038 for (h = s->proxy->req_cap; h; h = h->next) {
2039 if (s->req_cap[h->index] != NULL)
2040 pool_free_to(h->pool, s->req_cap[h->index]);
2041 }
2042 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
2043 }
2044
willy tarreaua1598082005-12-17 13:08:06 +01002045 if (s->logs.uri)
2046 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01002047 if (s->logs.cli_cookie)
2048 pool_free(capture, s->logs.cli_cookie);
2049 if (s->logs.srv_cookie)
2050 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01002051
willy tarreau5cbea6f2005-12-17 12:48:26 +01002052 pool_free(session, s);
2053}
2054
willy tarreau0f7af912005-12-17 12:21:26 +01002055
2056/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01002057 * This function recounts the number of usable active and backup servers for
2058 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002059 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01002060 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002061static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002062 struct server *srv;
2063
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002064 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002065 for (srv = px->srv; srv != NULL; srv = srv->next) {
2066 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002067 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002068 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002069 px->tot_wbck += srv->eweight + 1;
2070 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002071 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002072 px->tot_wact += srv->eweight + 1;
2073 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01002074 }
2075 }
2076}
2077
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002078/* This function recomputes the server map for proxy px. It
2079 * relies on px->tot_wact and px->tot_wbck, so it must be
2080 * called after recount_servers(). It also expects px->srv_map
2081 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01002082 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002083static void recalc_server_map(struct proxy *px) {
2084 int o, tot, flag;
2085 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01002086
willy tarreau4c8c2b52006-03-24 19:36:41 +01002087 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002088 flag = SRV_RUNNING;
2089 tot = px->tot_wact;
2090 } else if (px->srv_bck) {
2091 flag = SRV_RUNNING | SRV_BACKUP;
2092 if (px->options & PR_O_USE_ALL_BK)
2093 tot = px->tot_wbck;
2094 else
2095 tot = 1; /* the first server is enough */
2096 } else {
2097 px->srv_map_sz = 0;
2098 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002099 }
Willy TARREAU3481c462006-03-01 22:37:57 +01002100
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002101 /* this algorithm gives priority to the first server, which means that
2102 * it will respect the declaration order for equivalent weights, and
2103 * that whatever the weights, the first server called will always be
2104 * the first declard. This is an important asumption for the backup
2105 * case, where we want the first server only.
2106 */
2107 for (cur = px->srv; cur; cur = cur->next)
2108 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002109
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002110 for (o = 0; o < tot; o++) {
2111 int max = 0;
2112 best = NULL;
2113 for (cur = px->srv; cur; cur = cur->next) {
2114 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
2115 int v;
2116
2117 /* If we are forced to return only one server, we don't want to
2118 * go further, because we would return the wrong one due to
2119 * divide overflow.
2120 */
2121 if (tot == 1) {
2122 best = cur;
2123 break;
2124 }
2125
2126 cur->wscore += cur->eweight + 1;
2127 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
2128 if (best == NULL || v > max) {
2129 max = v;
2130 best = cur;
2131 }
2132 }
2133 }
2134 px->srv_map[o] = best;
2135 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002136 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002137 px->srv_map_sz = tot;
2138}
Willy TARREAU3481c462006-03-01 22:37:57 +01002139
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002140/*
willy tarreau898db9d2006-04-12 20:29:08 +02002141 * This function tries to find a running server with free connection slots for
2142 * the proxy <px> following the round-robin method.
2143 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2144 * to point to the next server. If no valid server is found, NULL is returned.
2145 */
2146static inline struct server *get_server_rr_with_conns(struct proxy *px) {
2147 int newidx;
2148 struct server *srv;
2149
2150 if (px->srv_map_sz == 0)
2151 return NULL;
2152
2153 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2154 px->srv_rr_idx = 0;
2155 newidx = px->srv_rr_idx;
2156
2157 do {
2158 srv = px->srv_map[newidx++];
2159 if (!srv->maxconn || srv->cur_sess < srv->maxconn) {
2160 px->srv_rr_idx = newidx;
2161 return srv;
2162 }
2163 if (newidx == px->srv_map_sz)
2164 newidx = 0;
2165 } while (newidx != px->srv_rr_idx);
2166
2167 return NULL;
2168}
2169
2170
2171/*
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002172 * This function tries to find a running server for the proxy <px> following
willy tarreau898db9d2006-04-12 20:29:08 +02002173 * the round-robin method.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002174 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2175 * to point to the next server. If no valid server is found, NULL is returned.
2176 */
2177static inline struct server *get_server_rr(struct proxy *px) {
2178 if (px->srv_map_sz == 0)
2179 return NULL;
2180
2181 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2182 px->srv_rr_idx = 0;
2183 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01002184}
2185
willy tarreau62084d42006-03-24 18:57:41 +01002186
2187/*
willy tarreau1a3442d2006-03-24 21:03:20 +01002188 * This function tries to find a running server for the proxy <px> following
2189 * the source hash method. Depending on the number of active/backup servers,
2190 * it will either look for active servers, or for backup servers.
2191 * If any server is found, it will be returned. If no valid server is found,
2192 * NULL is returned.
2193 */
2194static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002195 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01002196
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002197 if (px->srv_map_sz == 0)
2198 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01002199
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002200 l = h = 0;
willy tarreaucd655352006-04-29 12:11:46 +02002201 if (px->srv_act > 1 || (px->srv_act == 0 && px->srv_bck > 1)) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002202 while ((l + sizeof (int)) <= len) {
2203 h ^= ntohl(*(unsigned int *)(&addr[l]));
2204 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01002205 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002206 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01002207 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002208 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01002209}
2210
2211
2212/*
willy tarreaudfece232006-05-02 00:19:57 +02002213 * This function marks the session as 'assigned' in direct or dispatch modes,
2214 * or tries to assign one in balance mode, according to the algorithm. It does
2215 * nothing if the session had already been assigned a server.
2216 *
2217 * It may return :
willy tarreau000375f2006-05-09 23:15:58 +02002218 * SRV_STATUS_OK if everything is OK. s->srv will be valid.
2219 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
2220 * SRV_STATUS_FULL if all servers are saturated. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002221 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2222 *
2223 * Upon successful return, the session flag SN_ASSIGNED to indicate that it does
2224 * not need to be called anymore. This usually means that s->srv can be trusted
2225 * in balance and direct modes. This flag is not cleared, so it's to the caller
2226 * to clear it if required (eg: redispatch).
2227 *
willy tarreau0f7af912005-12-17 12:21:26 +01002228 */
willy tarreau0f7af912005-12-17 12:21:26 +01002229
willy tarreaudfece232006-05-02 00:19:57 +02002230int assign_server(struct session *s) {
willy tarreau12350152005-12-18 01:03:27 +01002231#ifdef DEBUG_FULL
willy tarreaudfece232006-05-02 00:19:57 +02002232 fprintf(stderr,"assign_server : s=%p\n",s);
willy tarreau12350152005-12-18 01:03:27 +01002233#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002234
willy tarreaudfece232006-05-02 00:19:57 +02002235 if (s->pend_pos)
2236 return SRV_STATUS_INTERNAL;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002237
willy tarreaudfece232006-05-02 00:19:57 +02002238 if (!(s->flags & SN_ASSIGNED)) {
2239 if ((s->proxy->options & PR_O_BALANCE) && !(s->flags & SN_DIRECT)) {
2240 if (!s->proxy->srv_act && !s->proxy->srv_bck)
2241 return SRV_STATUS_NOSRV;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002242
willy tarreaudfece232006-05-02 00:19:57 +02002243 if (s->proxy->options & PR_O_BALANCE_RR) {
2244 s->srv = get_server_rr_with_conns(s->proxy);
2245 if (!s->srv)
2246 return SRV_STATUS_FULL;
2247 }
2248 else if (s->proxy->options & PR_O_BALANCE_SH) {
2249 int len;
2250
2251 if (s->cli_addr.ss_family == AF_INET)
2252 len = 4;
2253 else if (s->cli_addr.ss_family == AF_INET6)
2254 len = 16;
2255 else /* unknown IP family */
2256 return SRV_STATUS_INTERNAL;
2257
2258 s->srv = get_server_sh(s->proxy,
2259 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2260 len);
2261 }
2262 else /* unknown balancing algorithm */
2263 return SRV_STATUS_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002264 }
willy tarreaudfece232006-05-02 00:19:57 +02002265 s->flags |= SN_ASSIGNED;
2266 }
2267 return SRV_STATUS_OK;
2268}
willy tarreau1a3442d2006-03-24 21:03:20 +01002269
willy tarreaudfece232006-05-02 00:19:57 +02002270/*
2271 * This function assigns a server address to a session, and sets SN_ADDR_SET.
2272 * The address is taken from the currently assigned server, or from the
2273 * dispatch or transparent address.
2274 *
2275 * It may return :
2276 * SRV_STATUS_OK if everything is OK.
2277 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2278 *
2279 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
2280 * not cleared, so it's to the caller to clear it if required.
2281 *
2282 */
2283int assign_server_address(struct session *s) {
2284#ifdef DEBUG_FULL
2285 fprintf(stderr,"assign_server_address : s=%p\n",s);
2286#endif
2287
2288 if (s->flags & SN_DIRECT || s->proxy->options & PR_O_BALANCE) {
2289 /* A server is necessarily known for this session */
2290 if (!(s->flags & SN_ASSIGNED))
2291 return SRV_STATUS_INTERNAL;
2292
2293 s->srv_addr = s->srv->addr;
willy tarreau1a3442d2006-03-24 21:03:20 +01002294
willy tarreaudfece232006-05-02 00:19:57 +02002295 /* if this server remaps proxied ports, we'll use
2296 * the port the client connected to with an offset. */
2297 if (s->srv->state & SRV_MAPPORTS) {
2298 struct sockaddr_in sockname;
2299 socklen_t namelen = sizeof(sockname);
2300
2301 if (!(s->proxy->options & PR_O_TRANSP) ||
2302 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2303 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2304 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
willy tarreau1a3442d2006-03-24 21:03:20 +01002305 }
willy tarreau0f7af912005-12-17 12:21:26 +01002306 }
willy tarreaua1598082005-12-17 13:08:06 +01002307 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002308 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002309 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002310 }
2311 else if (s->proxy->options & PR_O_TRANSP) {
2312 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002313 socklen_t salen = sizeof(s->srv_addr);
2314
willy tarreau5cbea6f2005-12-17 12:48:26 +01002315 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2316 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaudfece232006-05-02 00:19:57 +02002317 return SRV_STATUS_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002318 }
2319 }
willy tarreau0f7af912005-12-17 12:21:26 +01002320
willy tarreaudfece232006-05-02 00:19:57 +02002321 s->flags |= SN_ADDR_SET;
2322 return SRV_STATUS_OK;
2323}
willy tarreaua41a8b42005-12-17 14:02:24 +01002324
willy tarreaudfece232006-05-02 00:19:57 +02002325/* This function assigns a server to session <s> if required, and can add the
2326 * connection to either the assigned server's queue or to the proxy's queue.
2327 *
2328 * Returns :
2329 *
2330 * SRV_STATUS_OK if everything is OK.
willy tarreau000375f2006-05-09 23:15:58 +02002331 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002332 * SRV_STATUS_QUEUED if the connection has been queued.
2333 * SRV_STATUS_FULL if the server(s) is/are saturated and the
2334 * connection could not be queued.
2335 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2336 *
2337 */
2338int assign_server_and_queue(struct session *s) {
2339 struct pendconn *p;
2340 int err;
2341
2342 if (s->pend_pos)
2343 return SRV_STATUS_INTERNAL;
2344
2345 if (s->flags & SN_ASSIGNED) {
2346 /* a server does not need to be assigned, perhaps because we're in
2347 * direct mode, or in dispatch or transparent modes where the server
2348 * is not needed.
2349 */
2350 if (s->srv &&
2351 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2352 p = pendconn_add(s);
2353 if (p)
2354 return SRV_STATUS_QUEUED;
2355 else
2356 return SRV_STATUS_FULL;
2357 }
2358 return SRV_STATUS_OK;
2359 }
2360
2361 /* a server needs to be assigned */
2362 err = assign_server(s);
2363 switch (err) {
2364 case SRV_STATUS_OK:
2365 /* in balance mode, we might have servers with connection limits */
2366 if (s->srv != NULL &&
2367 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2368 p = pendconn_add(s);
2369 if (p)
2370 return SRV_STATUS_QUEUED;
2371 else
2372 return SRV_STATUS_FULL;
2373 }
2374 return SRV_STATUS_OK;
2375
2376 case SRV_STATUS_FULL:
2377 /* queue this session into the proxy's queue */
2378 p = pendconn_add(s);
2379 if (p)
2380 return SRV_STATUS_QUEUED;
2381 else
2382 return SRV_STATUS_FULL;
2383
2384 case SRV_STATUS_NOSRV:
2385 case SRV_STATUS_INTERNAL:
2386 return err;
2387 default:
2388 return SRV_STATUS_INTERNAL;
willy tarreaua41a8b42005-12-17 14:02:24 +01002389 }
willy tarreaudfece232006-05-02 00:19:57 +02002390}
2391
2392
2393/*
2394 * This function initiates a connection to the server assigned to this session
2395 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
2396 * It can return one of :
2397 * - SN_ERR_NONE if everything's OK
2398 * - SN_ERR_SRVTO if there are no more servers
2399 * - SN_ERR_SRVCL if the connection was refused by the server
2400 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
2401 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
2402 * - SN_ERR_INTERNAL for any other purely internal errors
2403 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
2404 */
2405int connect_server(struct session *s) {
2406 int fd, err;
2407
2408 if (!(s->flags & SN_ADDR_SET)) {
2409 err = assign_server_address(s);
2410 if (err != SRV_STATUS_OK)
2411 return SN_ERR_INTERNAL;
2412 }
willy tarreaua41a8b42005-12-17 14:02:24 +01002413
willy tarreau0f7af912005-12-17 12:21:26 +01002414 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002415 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002416
2417 if (errno == ENFILE)
2418 send_log(s->proxy, LOG_EMERG,
2419 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2420 s->proxy->id, maxfd);
2421 else if (errno == EMFILE)
2422 send_log(s->proxy, LOG_EMERG,
2423 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2424 s->proxy->id, maxfd);
2425 else if (errno == ENOBUFS || errno == ENOMEM)
2426 send_log(s->proxy, LOG_EMERG,
2427 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2428 s->proxy->id, maxfd);
2429 /* this is a resource error */
2430 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002431 }
2432
willy tarreau9fe663a2005-12-17 13:02:59 +01002433 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002434 /* do not log anything there, it's a normal condition when this option
2435 * is used to serialize connections to a server !
2436 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002437 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2438 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002439 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002440 }
2441
willy tarreau0f7af912005-12-17 12:21:26 +01002442 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2443 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002444 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002445 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002446 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002447 }
2448
willy tarreaub952e1d2005-12-18 01:31:20 +01002449 if (s->proxy->options & PR_O_TCP_SRV_KA)
2450 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2451
willy tarreau0174f312005-12-18 01:02:42 +01002452 /* allow specific binding :
2453 * - server-specific at first
2454 * - proxy-specific next
2455 */
2456 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2457 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2458 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2459 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2460 s->proxy->id, s->srv->id);
2461 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002462 send_log(s->proxy, LOG_EMERG,
2463 "Cannot bind to source address before connect() for server %s/%s.\n",
2464 s->proxy->id, s->srv->id);
2465 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002466 }
2467 }
2468 else if (s->proxy->options & PR_O_BIND_SRC) {
2469 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2470 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2471 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2472 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002473 send_log(s->proxy, LOG_EMERG,
2474 "Cannot bind to source address before connect() for server %s/%s.\n",
2475 s->proxy->id, s->srv->id);
2476 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002477 }
willy tarreaua1598082005-12-17 13:08:06 +01002478 }
2479
willy tarreaub1285d52005-12-18 01:20:14 +01002480 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2481 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2482
2483 if (errno == EAGAIN || errno == EADDRINUSE) {
2484 char *msg;
2485 if (errno == EAGAIN) /* no free ports left, try again later */
2486 msg = "no free ports";
2487 else
2488 msg = "local address already in use";
2489
2490 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002491 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002492 send_log(s->proxy, LOG_EMERG,
2493 "Connect() failed for server %s/%s: %s.\n",
2494 s->proxy->id, s->srv->id, msg);
2495 return SN_ERR_RESOURCE;
2496 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002497 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002498 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002499 return SN_ERR_SRVTO;
2500 } else {
2501 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002502 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002503 close(fd);
2504 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002505 }
2506 }
2507
willy tarreau5cbea6f2005-12-17 12:48:26 +01002508 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002509 fdtab[fd].read = &event_srv_read;
2510 fdtab[fd].write = &event_srv_write;
2511 fdtab[fd].state = FD_STCONN; /* connection in progress */
2512
2513 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002514#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2515 if (PrevReadEvent) {
2516 assert(!(FD_ISSET(fd, PrevReadEvent)));
2517 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2518 }
2519#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002520
2521 fd_insert(fd);
willy tarreaucb406512006-05-18 00:52:35 +02002522 if (s->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02002523 s->srv->cur_sess++;
willy tarreaucb406512006-05-18 00:52:35 +02002524 if (s->srv->cur_sess > s->srv->cur_sess_max)
2525 s->srv->cur_sess_max = s->srv->cur_sess;
2526 }
willy tarreau0f7af912005-12-17 12:21:26 +01002527
2528 if (s->proxy->contimeout)
2529 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2530 else
2531 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002532 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002533}
2534
2535/*
2536 * this function is called on a read event from a client socket.
2537 * It returns 0.
2538 */
2539int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002540 struct task *t = fdtab[fd].owner;
2541 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002542 struct buffer *b = s->req;
2543 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002544
willy tarreau12350152005-12-18 01:03:27 +01002545#ifdef DEBUG_FULL
2546 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2547#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002548
willy tarreau0f7af912005-12-17 12:21:26 +01002549 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002550#ifdef FILL_BUFFERS
2551 while (1)
2552#else
2553 do
2554#endif
2555 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002556 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2557 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002558 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002559 }
2560 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002561 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002562 }
2563 else {
2564 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002565 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2566 * since it means that the rewrite protection has been removed. This
2567 * implies that the if statement can be removed.
2568 */
2569 if (max > b->rlim - b->data)
2570 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002571 }
2572
2573 if (max == 0) { /* not anymore room to store data */
2574 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002575 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002576 }
2577
willy tarreau3242e862005-12-17 12:27:53 +01002578#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002579 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002580 int skerr;
2581 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002582
willy tarreau5cbea6f2005-12-17 12:48:26 +01002583 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2584 if (skerr)
2585 ret = -1;
2586 else
2587 ret = recv(fd, b->r, max, 0);
2588 }
willy tarreau3242e862005-12-17 12:27:53 +01002589#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002590 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002591#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002592 if (ret > 0) {
2593 b->r += ret;
2594 b->l += ret;
2595 s->res_cr = RES_DATA;
2596
2597 if (b->r == b->data + BUFSIZE) {
2598 b->r = b->data; /* wrap around the buffer */
2599 }
willy tarreaua1598082005-12-17 13:08:06 +01002600
2601 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002602 /* we hope to read more data or to get a close on next round */
2603 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002604 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002605 else if (ret == 0) {
2606 s->res_cr = RES_NULL;
2607 break;
2608 }
2609 else if (errno == EAGAIN) {/* ignore EAGAIN */
2610 break;
2611 }
2612 else {
2613 s->res_cr = RES_ERROR;
2614 fdtab[fd].state = FD_STERROR;
2615 break;
2616 }
2617 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002618#ifndef FILL_BUFFERS
2619 while (0);
2620#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002621 }
2622 else {
2623 s->res_cr = RES_ERROR;
2624 fdtab[fd].state = FD_STERROR;
2625 }
2626
willy tarreau5cbea6f2005-12-17 12:48:26 +01002627 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002628 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002629 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2630 else
2631 tv_eternity(&s->crexpire);
2632
2633 task_wakeup(&rq, t);
2634 }
willy tarreau0f7af912005-12-17 12:21:26 +01002635
willy tarreau0f7af912005-12-17 12:21:26 +01002636 return 0;
2637}
2638
2639
2640/*
2641 * this function is called on a read event from a server socket.
2642 * It returns 0.
2643 */
2644int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002645 struct task *t = fdtab[fd].owner;
2646 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002647 struct buffer *b = s->rep;
2648 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002649
willy tarreau12350152005-12-18 01:03:27 +01002650#ifdef DEBUG_FULL
2651 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2652#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002653
willy tarreau0f7af912005-12-17 12:21:26 +01002654 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002655#ifdef FILL_BUFFERS
2656 while (1)
2657#else
2658 do
2659#endif
2660 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002661 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2662 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002663 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002664 }
2665 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002666 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002667 }
2668 else {
2669 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002670 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2671 * since it means that the rewrite protection has been removed. This
2672 * implies that the if statement can be removed.
2673 */
2674 if (max > b->rlim - b->data)
2675 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002676 }
2677
2678 if (max == 0) { /* not anymore room to store data */
2679 FD_CLR(fd, StaticReadEvent);
2680 break;
2681 }
2682
willy tarreau3242e862005-12-17 12:27:53 +01002683#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002684 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002685 int skerr;
2686 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002687
willy tarreau5cbea6f2005-12-17 12:48:26 +01002688 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2689 if (skerr)
2690 ret = -1;
2691 else
2692 ret = recv(fd, b->r, max, 0);
2693 }
willy tarreau3242e862005-12-17 12:27:53 +01002694#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002695 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002696#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002697 if (ret > 0) {
2698 b->r += ret;
2699 b->l += ret;
2700 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002701
willy tarreau5cbea6f2005-12-17 12:48:26 +01002702 if (b->r == b->data + BUFSIZE) {
2703 b->r = b->data; /* wrap around the buffer */
2704 }
willy tarreaua1598082005-12-17 13:08:06 +01002705
2706 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002707 /* we hope to read more data or to get a close on next round */
2708 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002709 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002710 else if (ret == 0) {
2711 s->res_sr = RES_NULL;
2712 break;
2713 }
2714 else if (errno == EAGAIN) {/* ignore EAGAIN */
2715 break;
2716 }
2717 else {
2718 s->res_sr = RES_ERROR;
2719 fdtab[fd].state = FD_STERROR;
2720 break;
2721 }
2722 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002723#ifndef FILL_BUFFERS
2724 while (0);
2725#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002726 }
2727 else {
2728 s->res_sr = RES_ERROR;
2729 fdtab[fd].state = FD_STERROR;
2730 }
2731
willy tarreau5cbea6f2005-12-17 12:48:26 +01002732 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002733 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002734 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2735 else
2736 tv_eternity(&s->srexpire);
2737
2738 task_wakeup(&rq, t);
2739 }
willy tarreau0f7af912005-12-17 12:21:26 +01002740
willy tarreau0f7af912005-12-17 12:21:26 +01002741 return 0;
2742}
2743
2744/*
2745 * this function is called on a write event from a client socket.
2746 * It returns 0.
2747 */
2748int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002749 struct task *t = fdtab[fd].owner;
2750 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002751 struct buffer *b = s->rep;
2752 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002753
willy tarreau12350152005-12-18 01:03:27 +01002754#ifdef DEBUG_FULL
2755 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2756#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002757
2758 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002759 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002760 // max = BUFSIZE; BUG !!!!
2761 max = 0;
2762 }
2763 else if (b->r > b->w) {
2764 max = b->r - b->w;
2765 }
2766 else
2767 max = b->data + BUFSIZE - b->w;
2768
willy tarreau0f7af912005-12-17 12:21:26 +01002769 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002770 if (max == 0) {
2771 s->res_cw = RES_NULL;
2772 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002773 tv_eternity(&s->cwexpire);
2774 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002775 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002776 }
2777
willy tarreau3242e862005-12-17 12:27:53 +01002778#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002779 {
2780 int skerr;
2781 socklen_t lskerr = sizeof(skerr);
2782
2783 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2784 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002785 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002786 else
willy tarreau3242e862005-12-17 12:27:53 +01002787 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002788 }
willy tarreau3242e862005-12-17 12:27:53 +01002789#else
willy tarreau0f7af912005-12-17 12:21:26 +01002790 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002791#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002792
2793 if (ret > 0) {
2794 b->l -= ret;
2795 b->w += ret;
2796
2797 s->res_cw = RES_DATA;
2798
2799 if (b->w == b->data + BUFSIZE) {
2800 b->w = b->data; /* wrap around the buffer */
2801 }
2802 }
2803 else if (ret == 0) {
2804 /* nothing written, just make as if we were never called */
2805// s->res_cw = RES_NULL;
2806 return 0;
2807 }
2808 else if (errno == EAGAIN) /* ignore EAGAIN */
2809 return 0;
2810 else {
2811 s->res_cw = RES_ERROR;
2812 fdtab[fd].state = FD_STERROR;
2813 }
2814 }
2815 else {
2816 s->res_cw = RES_ERROR;
2817 fdtab[fd].state = FD_STERROR;
2818 }
2819
willy tarreaub1ff9db2005-12-17 13:51:03 +01002820 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002821 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002822 /* FIXME: to prevent the client from expiring read timeouts during writes,
2823 * we refresh it. A solution would be to merge read+write timeouts into a
2824 * unique one, although that needs some study particularly on full-duplex
2825 * TCP connections. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002826 s->crexpire = s->cwexpire;
2827 }
willy tarreau0f7af912005-12-17 12:21:26 +01002828 else
2829 tv_eternity(&s->cwexpire);
2830
willy tarreau5cbea6f2005-12-17 12:48:26 +01002831 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002832 return 0;
2833}
2834
2835
2836/*
2837 * this function is called on a write event from a server socket.
2838 * It returns 0.
2839 */
2840int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002841 struct task *t = fdtab[fd].owner;
2842 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002843 struct buffer *b = s->req;
2844 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002845
willy tarreau12350152005-12-18 01:03:27 +01002846#ifdef DEBUG_FULL
2847 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2848#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002849
2850 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002851 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002852 // max = BUFSIZE; BUG !!!!
2853 max = 0;
2854 }
2855 else if (b->r > b->w) {
2856 max = b->r - b->w;
2857 }
2858 else
2859 max = b->data + BUFSIZE - b->w;
2860
willy tarreau0f7af912005-12-17 12:21:26 +01002861 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002862 if (max == 0) {
2863 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002864 if (s->srv_state == SV_STCONN) {
2865 int skerr;
2866 socklen_t lskerr = sizeof(skerr);
2867 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2868 if (skerr) {
2869 s->res_sw = RES_ERROR;
2870 fdtab[fd].state = FD_STERROR;
2871 task_wakeup(&rq, t);
2872 tv_eternity(&s->swexpire);
2873 FD_CLR(fd, StaticWriteEvent);
2874 return 0;
2875 }
2876 }
2877
willy tarreau0f7af912005-12-17 12:21:26 +01002878 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002879 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002880 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002881 tv_eternity(&s->swexpire);
2882 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002883 return 0;
2884 }
2885
willy tarreau3242e862005-12-17 12:27:53 +01002886#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002887 {
2888 int skerr;
2889 socklen_t lskerr = sizeof(skerr);
2890 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2891 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002892 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002893 else
willy tarreau3242e862005-12-17 12:27:53 +01002894 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002895 }
willy tarreau3242e862005-12-17 12:27:53 +01002896#else
willy tarreau0f7af912005-12-17 12:21:26 +01002897 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002898#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002899 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002900 if (ret > 0) {
2901 b->l -= ret;
2902 b->w += ret;
2903
2904 s->res_sw = RES_DATA;
2905
2906 if (b->w == b->data + BUFSIZE) {
2907 b->w = b->data; /* wrap around the buffer */
2908 }
2909 }
2910 else if (ret == 0) {
2911 /* nothing written, just make as if we were never called */
2912 // s->res_sw = RES_NULL;
2913 return 0;
2914 }
2915 else if (errno == EAGAIN) /* ignore EAGAIN */
2916 return 0;
2917 else {
2918 s->res_sw = RES_ERROR;
2919 fdtab[fd].state = FD_STERROR;
2920 }
2921 }
2922 else {
2923 s->res_sw = RES_ERROR;
2924 fdtab[fd].state = FD_STERROR;
2925 }
2926
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002927 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2928 * otherwise it could loop indefinitely !
2929 */
2930 if (s->srv_state != SV_STCONN) {
2931 if (s->proxy->srvtimeout) {
2932 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002933 /* FIXME: to prevent the server from expiring read timeouts during writes,
2934 * we refresh it. A solution would be to merge read+write+connect timeouts
2935 * into a unique one since we don't mind expiring on read or write, and none
2936 * of them is enabled while waiting for connect(), although that needs some
2937 * study particularly on full-duplex TCP connections. */
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002938 s->srexpire = s->swexpire;
2939 }
2940 else
2941 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002942 }
willy tarreau0f7af912005-12-17 12:21:26 +01002943
willy tarreau5cbea6f2005-12-17 12:48:26 +01002944 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002945 return 0;
2946}
2947
2948
willy tarreaue0331262006-05-15 03:02:46 +02002949/* returns 1 if the buffer is empty, 0 otherwise */
2950static inline int buffer_isempty(struct buffer *buf) {
2951 return buf->l == 0;
2952}
2953
2954
2955/* returns 1 if the buffer is full, 0 otherwise */
2956static inline int buffer_isfull(struct buffer *buf) {
2957 return buf->l == BUFSIZE;
2958}
2959
2960
2961/* flushes any content from buffer <buf> */
2962void buffer_flush(struct buffer *buf) {
2963 buf->r = buf->h = buf->lr = buf->w = buf->data;
2964 buf->l = 0;
2965}
2966
2967
2968/* returns the maximum number of bytes writable at once in this buffer */
2969int buffer_max(struct buffer *buf) {
willy tarreaucb406512006-05-18 00:52:35 +02002970 if (buf->l == BUFSIZE)
2971 return 0;
2972 else if (buf->r >= buf->w)
willy tarreaue0331262006-05-15 03:02:46 +02002973 return buf->data + BUFSIZE - buf->r;
2974 else
2975 return buf->w - buf->r;
2976}
2977
2978
willy tarreau0f7af912005-12-17 12:21:26 +01002979/*
willy tarreaue0331262006-05-15 03:02:46 +02002980 * Tries to realign the given buffer, and returns how many bytes can be written
2981 * there at once without overwriting anything.
2982 */
2983int buffer_realign(struct buffer *buf) {
2984 if (buf->l == 0) {
2985 /* let's realign the buffer to optimize I/O */
willy tarreaucb406512006-05-18 00:52:35 +02002986 buf->r = buf->w = buf->h = buf->lr = buf->data;
willy tarreaue0331262006-05-15 03:02:46 +02002987 }
2988 return buffer_max(buf);
2989}
2990
2991
2992/* writes <len> bytes from message <msg> to buffer <buf>. Returns 0 in case of
2993 * success, or the number of bytes available otherwise.
willy tarreau1f431b52006-05-21 14:46:15 +02002994 * FIXME-20060521: handle unaligned data.
willy tarreaue0331262006-05-15 03:02:46 +02002995 */
2996int buffer_write(struct buffer *buf, const char *msg, int len) {
2997 int max;
2998
willy tarreaucb406512006-05-18 00:52:35 +02002999 max = buffer_realign(buf);
willy tarreaue0331262006-05-15 03:02:46 +02003000
3001 if (len > max)
3002 return max;
3003
3004 memcpy(buf->r, msg, len);
3005 buf->l += len;
3006 buf->r += len;
3007 if (buf->r == buf->data + BUFSIZE)
willy tarreaucb406512006-05-18 00:52:35 +02003008 buf->r = buf->data;
willy tarreaue0331262006-05-15 03:02:46 +02003009 return 0;
3010}
3011
3012
3013/*
willy tarreaue39cd132005-12-17 13:00:18 +01003014 * returns a message to the client ; the connection is shut down for read,
3015 * and the request is cleared so that no server connection can be initiated.
3016 * The client must be in a valid state for this (HEADER, DATA ...).
3017 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01003018 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01003019 */
3020void client_retnclose(struct session *s, int len, const char *msg) {
3021 FD_CLR(s->cli_fd, StaticReadEvent);
3022 FD_SET(s->cli_fd, StaticWriteEvent);
3023 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01003024 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01003025 shutdown(s->cli_fd, SHUT_RD);
3026 s->cli_state = CL_STSHUTR;
willy tarreaue0331262006-05-15 03:02:46 +02003027 buffer_flush(s->rep);
3028 buffer_write(s->rep, msg, len);
willy tarreaue39cd132005-12-17 13:00:18 +01003029 s->req->l = 0;
3030}
3031
3032
3033/*
3034 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01003035 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01003036 */
3037void client_return(struct session *s, int len, const char *msg) {
willy tarreaue0331262006-05-15 03:02:46 +02003038 buffer_flush(s->rep);
3039 buffer_write(s->rep, msg, len);
willy tarreaue39cd132005-12-17 13:00:18 +01003040 s->req->l = 0;
3041}
3042
willy tarreaue0331262006-05-15 03:02:46 +02003043/*
3044 * Produces data for the session <s> depending on its source. Expects to be
3045 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3046 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3047 * session, which it uses to keep on being called when there is free space in
3048 * the buffer, of simply by letting an empty buffer upon return. It returns 1
3049 * if it changes the session state from CL_STSHUTR, otherwise 0.
3050 */
3051int produce_content(struct session *s) {
3052 struct buffer *rep = s->rep;
3053 struct proxy *px;
3054 struct server *sv;
willy tarreaucb406512006-05-18 00:52:35 +02003055 int msglen;
willy tarreaue0331262006-05-15 03:02:46 +02003056
3057 if (s->data_source == DATA_SRC_NONE) {
3058 s->flags &= ~SN_SELF_GEN;
3059 return 1;
3060 }
3061 else if (s->data_source == DATA_SRC_STATS) {
willy tarreau1f431b52006-05-21 14:46:15 +02003062 msglen = 0;
3063
3064 if (s->data_state == DATA_ST_INIT) { /* the function had not been called yet */
3065 unsigned int up;
3066
willy tarreaue0331262006-05-15 03:02:46 +02003067 s->flags |= SN_SELF_GEN; // more data will follow
willy tarreau1f431b52006-05-21 14:46:15 +02003068
3069 /* send the start of the HTTP response */
3070 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003071 "HTTP/1.0 200 OK\r\n"
3072 "Cache-Control: no-cache\r\n"
3073 "Connection: close\r\n"
3074 "\r\n\r\n");
3075
3076 s->logs.status = 200;
3077 client_retnclose(s, msglen, trash); // send the start of the response.
willy tarreau1f431b52006-05-21 14:46:15 +02003078 msglen = 0;
3079
willy tarreaue0331262006-05-15 03:02:46 +02003080 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
3081 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
3082 if (!(s->flags & SN_FINST_MASK))
3083 s->flags |= SN_FINST_R;
3084
3085 /* WARNING! This must fit in the first buffer !!! */
willy tarreau1f431b52006-05-21 14:46:15 +02003086 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003087 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
3088 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
3089 "<style type=\"text/css\"><!--\n"
3090 "body {"
3091 " font-family: helvetica, arial;"
3092 " font-size: 12px;"
3093 " font-weight: normal;"
3094 " color: black;"
3095 " background: white;"
3096 "}\n"
3097 "td {"
3098 " font-size: 12px;"
willy tarreaucb406512006-05-18 00:52:35 +02003099 " align: center;"
willy tarreaue0331262006-05-15 03:02:46 +02003100 "}\n"
3101 "h1 {"
3102 " font-size: xx-large;"
3103 " margin-bottom: 0.5em;"
3104 "}\n"
3105 "h2 {"
3106 " font-family: helvetica, arial;"
3107 " font-size: x-large;"
3108 " font-weight: bold;"
3109 " font-style: italic;"
3110 " color: #6020a0;"
3111 " margin-top: 0em;"
3112 " margin-bottom: 0em;"
3113 "}\n"
3114 "h3 {"
3115 " font-family: helvetica, arial;"
3116 " font-size: 16px;"
3117 " font-weight: bold;"
3118 " color: #b00040;"
3119 " background: #e8e8d0;"
3120 " margin-top: 0em;"
3121 " margin-bottom: 0em;"
3122 "}\n"
3123 "li {"
3124 " margin-top: 0.25em;"
3125 " margin-right: 2em;"
3126 "}\n"
3127 ".hr {"
3128 " margin-top: 0.25em;"
3129 " border-color: black;"
3130 " border-bottom-style: solid;"
willy tarreaucb406512006-05-18 00:52:35 +02003131 "}\n"
3132 "table.tbl { border-collapse: collapse; border-width: 1px; border-style: solid; border-color: gray;}\n"
3133 "table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; border-color: gray; }\n"
3134 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray; }\n"
3135 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
3136 "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 +02003137 "-->"
3138 "</style></head>");
3139
willy tarreaucb406512006-05-18 00:52:35 +02003140 if (buffer_write(rep, trash, msglen) != 0)
3141 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003142 msglen = 0;
willy tarreaue0331262006-05-15 03:02:46 +02003143
3144 up = (now.tv_sec - start_date.tv_sec);
3145
3146 /* WARNING! this has to fit the first packet too */
willy tarreau1f431b52006-05-21 14:46:15 +02003147 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003148 "<body><h1>" PRODUCT_NAME "</h1>\n"
3149 "<h2>Statistics Report for pid %d</h2>\n"
3150 "<hr width=\"100%%\" class=\"hr\">\n"
willy tarreau338be832006-05-21 08:58:06 +02003151 "<h3>&gt; General process information</h3>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003152 "<table border=0><tr><td align=\"left\">\n"
willy tarreaue0331262006-05-15 03:02:46 +02003153 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
3154 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
willy tarreau338be832006-05-21 08:58:06 +02003155 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
willy tarreaue0331262006-05-15 03:02:46 +02003156 "<b>maxsock = </b> %d<br>\n"
3157 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003158 "</td><td width=\"10%%\">\n"
3159 "</td><td align=\"right\">\n"
3160 "<table class=\"lgd\">"
3161 "<tr><td bgcolor=\"#C0FFC0\">&nbsp;</td><td style=\"border-style: none;\">active UP </td>"
3162 "<td bgcolor=\"#B0D0FF\">&nbsp;</td><td style=\"border-style: none;\">backup UP </td></tr>"
3163 "<tr><td bgcolor=\"#FFFFA0\"></td><td style=\"border-style: none;\">active UP, going down </td>"
3164 "<td bgcolor=\"#C060FF\"></td><td style=\"border-style: none;\">backup UP, going down </td></tr>"
3165 "<tr><td bgcolor=\"#FFD020\"></td><td style=\"border-style: none;\">active DOWN, going up </td>"
3166 "<td bgcolor=\"#FF80FF\"></td><td style=\"border-style: none;\">backup DOWN, going up </td></tr>"
3167 "<tr><td bgcolor=\"#FF9090\"></td><td style=\"border-style: none;\">active or backup DOWN &nbsp;</td>"
3168 "<td bgcolor=\"#E0E0E0\"></td><td style=\"border-style: none;\">not checked </td></tr>"
3169 "</table>\n"
3170 "</tr></table>\n"
willy tarreaue0331262006-05-15 03:02:46 +02003171 "",
3172 pid, pid, global.nbproc,
3173 up / 86400, (up % 86400) / 3600,
3174 (up % 3600) / 60, (up % 60),
willy tarreau338be832006-05-21 08:58:06 +02003175 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
3176 global.rlimit_memmax ? " MB" : "",
willy tarreaue0331262006-05-15 03:02:46 +02003177 global.rlimit_nofile,
3178 global.maxsock,
3179 global.maxconn,
3180 actconn
3181 );
willy tarreaucb406512006-05-18 00:52:35 +02003182
3183 if (buffer_write(rep, trash, msglen) != 0)
3184 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003185 msglen = 0;
3186
3187 s->data_state = DATA_ST_DATA;
3188 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
3189
willy tarreaue0331262006-05-15 03:02:46 +02003190 px = s->data_ctx.stats.px = proxy;
willy tarreau1f431b52006-05-21 14:46:15 +02003191 s->data_ctx.stats.px_st = DATA_ST_INIT;
willy tarreaue0331262006-05-15 03:02:46 +02003192 }
3193
3194 while (s->data_ctx.stats.px) {
willy tarreaucb406512006-05-18 00:52:35 +02003195 int dispatch_sess, dispatch_cum;
willy tarreau1f431b52006-05-21 14:46:15 +02003196 int failed_checks, down_trans;
willy tarreaue3b30652006-05-21 16:23:22 +02003197 int failed_secu, failed_conns, failed_resp;
willy tarreaucb406512006-05-18 00:52:35 +02003198
willy tarreau1f431b52006-05-21 14:46:15 +02003199 if (s->data_ctx.stats.px_st == DATA_ST_INIT) {
3200 /* we are on a new proxy */
willy tarreaue0331262006-05-15 03:02:46 +02003201 px = s->data_ctx.stats.px;
willy tarreau1f431b52006-05-21 14:46:15 +02003202
3203 /* skip the disabled proxies */
3204 if (px->state == PR_STSTOPPED)
3205 goto next_proxy;
3206
3207 if (s->proxy->uri_auth && s->proxy->uri_auth->scope) {
3208 /* we have a limited scope, we have to check the proxy name */
3209 struct stat_scope *scope;
3210 int len;
3211
3212 len = strlen(px->id);
3213 scope = s->proxy->uri_auth->scope;
3214
3215 while (scope) {
3216 /* match exact proxy name */
3217 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
3218 break;
3219
3220 /* match '.' which means 'self' proxy */
3221 if (!strcmp(scope->px_id, ".") && px == s->proxy)
3222 break;
3223 scope = scope->next;
3224 }
3225
3226 /* proxy name not found */
3227 if (scope == NULL)
3228 goto next_proxy;
3229 }
3230
3231 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003232 "<h3>&gt; Proxy instance %s : "
3233 "%d conns (maxconn=%d), %d queued (%d unassigned), %d total conns</h3>\n"
3234 "",
3235 px->id,
3236 px->nbconn, px->maxconn, px->totpend, px->nbpend, px->cum_conn);
3237
3238 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue3b30652006-05-21 16:23:22 +02003239 "<table cols=\"16\" class=\"tbl\">\n"
willy tarreaucb406512006-05-18 00:52:35 +02003240 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
3241 "<th colspan=5>Server</th>"
3242 "<th colspan=2>Queue</th>"
3243 "<th colspan=4>Sessions</th>"
willy tarreaue3b30652006-05-21 16:23:22 +02003244 "<th colspan=5>Errors</th></tr>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003245 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
3246 "<th>Name</th><th>Weight</th><th>Status</th><th>Act.</th><th>Bck.</th>"
3247 "<th>Curr.</th><th>Max.</th>"
3248 "<th>Curr.</th><th>Max.</th><th>Limit</th><th>Cumul.</th>"
willy tarreaue3b30652006-05-21 16:23:22 +02003249 "<th>Conn.</th><th>Resp.</th><th>Sec.</th><th>Check</th><th>Down</th></tr>\n");
willy tarreaue0331262006-05-15 03:02:46 +02003250
3251 if (buffer_write(rep, trash, msglen) != 0)
3252 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003253 msglen = 0;
3254
willy tarreaue0331262006-05-15 03:02:46 +02003255 s->data_ctx.stats.sv = px->srv;
willy tarreau1f431b52006-05-21 14:46:15 +02003256 s->data_ctx.stats.px_st = DATA_ST_DATA;
willy tarreaue0331262006-05-15 03:02:46 +02003257 }
3258
willy tarreaucb406512006-05-18 00:52:35 +02003259 px = s->data_ctx.stats.px;
3260
willy tarreau1f431b52006-05-21 14:46:15 +02003261 /* stats.sv has been initialized above */
willy tarreaue0331262006-05-15 03:02:46 +02003262 while (s->data_ctx.stats.sv != NULL) {
willy tarreaucb406512006-05-18 00:52:35 +02003263 static char *act_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FFD020", /*failing*/"#FFFFA0", /*up*/"#C0FFC0", /*unchecked*/"#E0E0E0" };
3264 static char *bck_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FF80ff", /*failing*/"#C060FF", /*up*/"#B0D0FF", /*unchecked*/"#E0E0E0" };
3265 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
3266 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP */
3267
willy tarreaue0331262006-05-15 03:02:46 +02003268 sv = s->data_ctx.stats.sv;
willy tarreaucb406512006-05-18 00:52:35 +02003269
willy tarreaucb406512006-05-18 00:52:35 +02003270 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
3271 if (!(sv->state & SRV_CHECKED))
3272 sv_state = 4;
3273 else if (sv->state & SRV_RUNNING)
3274 if (sv->health == sv->rise + sv->fall - 1)
3275 sv_state = 3; /* UP */
3276 else
3277 sv_state = 2; /* going down */
3278 else
3279 if (sv->health)
3280 sv_state = 1; /* going up */
3281 else
3282 sv_state = 0; /* DOWN */
3283
3284 /* name, weight */
willy tarreau1f431b52006-05-21 14:46:15 +02003285 msglen += snprintf(trash, sizeof(trash),
willy tarreaucb406512006-05-18 00:52:35 +02003286 "<tr align=center bgcolor=\"%s\"><td>%s</td><td>%d</td><td>",
3287 (sv->state & SRV_BACKUP) ? bck_tab_bg[sv_state] : act_tab_bg[sv_state],
3288 sv->id, sv->uweight+1);
3289 /* status */
3290 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, srv_hlt_st[sv_state],
3291 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
3292 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
3293
3294 /* act, bck */
3295 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3296 "</td><td>%s</td><td>%s</td>",
willy tarreaue0331262006-05-15 03:02:46 +02003297 (sv->state & SRV_BACKUP) ? "-" : "Y",
3298 (sv->state & SRV_BACKUP) ? "Y" : "-");
willy tarreaucb406512006-05-18 00:52:35 +02003299
3300 /* queue : current, max */
3301 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3302 "<td align=right>%d</td><td align=right>%d</td>",
3303 sv->nbpend, sv->nbpend_max);
3304
3305 /* sessions : current, max, limit, cumul */
3306 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3307 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>",
3308 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess);
3309
willy tarreaue3b30652006-05-21 16:23:22 +02003310 /* errors : connect, response, security */
3311 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3312 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3313 sv->failed_conns, sv->failed_resp, sv->failed_secu);
3314
3315 /* check failures : unique, fatal */
willy tarreau338be832006-05-21 08:58:06 +02003316 if (sv->state & SRV_CHECKED)
3317 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3318 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3319 sv->failed_checks, sv->down_trans);
3320 else
3321 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3322 "<td align=right>-</td><td align=right>-</td></tr>\n");
willy tarreaucb406512006-05-18 00:52:35 +02003323
willy tarreau1f431b52006-05-21 14:46:15 +02003324 if (buffer_write(rep, trash, msglen) != 0)
3325 return 0;
3326 msglen = 0;
3327
3328 s->data_ctx.stats.sv = sv->next;
3329 } /* while sv */
3330
3331 /* now we are past the last server, we'll dump information about the dispatcher */
3332
3333 /* We have to count down from the proxy to the servers to tell how
3334 * many sessions are on the dispatcher, and how many checks have
3335 * failed. We cannot count this during the servers dump because it
3336 * might be interrupted multiple times.
3337 */
3338 dispatch_sess = px->nbconn;
willy tarreaue3b30652006-05-21 16:23:22 +02003339 dispatch_cum = px->cum_conn;
3340 failed_secu = px->failed_secu;
3341 failed_conns = px->failed_conns;
3342 failed_resp = px->failed_resp;
willy tarreau1f431b52006-05-21 14:46:15 +02003343 failed_checks = down_trans = 0;
3344
3345 sv = px->srv;
3346 while (sv) {
3347 dispatch_sess -= sv->cur_sess;
3348 dispatch_cum -= sv->cum_sess;
willy tarreaue3b30652006-05-21 16:23:22 +02003349 failed_conns -= sv->failed_conns;
3350 failed_resp -= sv->failed_resp;
3351 failed_secu -= sv->failed_secu;
3352 if (sv->state & SRV_CHECKED) {
3353 failed_checks += sv->failed_checks;
3354 down_trans += sv->down_trans;
3355 }
willy tarreaue0331262006-05-15 03:02:46 +02003356 sv = sv->next;
willy tarreau1f431b52006-05-21 14:46:15 +02003357 }
willy tarreaucb406512006-05-18 00:52:35 +02003358
willy tarreau1f431b52006-05-21 14:46:15 +02003359 /* name, weight, status, act, bck */
3360 msglen += snprintf(trash + msglen, sizeof(trash),
3361 "<tr align=center bgcolor=\"#e8e8d0\">"
3362 "<td>Dispatcher</td><td>-</td>"
3363 "<td>%s</td><td>-</td><td>-</td>",
3364 px->state == PR_STRUN ? "UP" : "DOWN");
willy tarreaucb406512006-05-18 00:52:35 +02003365
willy tarreau1f431b52006-05-21 14:46:15 +02003366 /* queue : current, max */
3367 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3368 "<td align=right>%d</td><td align=right>%d</td>",
3369 px->nbpend, px->nbpend_max);
willy tarreaucb406512006-05-18 00:52:35 +02003370
willy tarreau1f431b52006-05-21 14:46:15 +02003371 /* sessions : current, max, limit, cumul. */
3372 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3373 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>",
3374 dispatch_sess, px->nbconn_max, px->maxconn, dispatch_cum);
willy tarreaucb406512006-05-18 00:52:35 +02003375
willy tarreaue3b30652006-05-21 16:23:22 +02003376 /* errors : connect, response, security */
3377 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3378 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3379 failed_conns, failed_resp, failed_secu);
3380
3381 /* check failures : unique, fatal */
willy tarreau1f431b52006-05-21 14:46:15 +02003382 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3383 "<td align=right>-</td><td align=right>-</td></tr>\n");
willy tarreaucb406512006-05-18 00:52:35 +02003384
willy tarreaucb406512006-05-18 00:52:35 +02003385
willy tarreau1f431b52006-05-21 14:46:15 +02003386 /* now the summary for the whole proxy */
3387 /* name, weight, status, act, bck */
3388 msglen += snprintf(trash + msglen, sizeof(trash),
3389 "<tr align=center style=\"color: #ffff80; background: #20C0C0;\">"
3390 "<td><b>Total</b></td><td>-</td>"
3391 "<td><b>%s</b></td><td><b>%d</b></td><td><b>%d</b></td>",
3392 (px->state == PR_STRUN && ((px->srv == NULL) || px->srv_act || px->srv_bck)) ? "UP" : "DOWN",
3393 px->srv_act, px->srv_bck);
willy tarreaucb406512006-05-18 00:52:35 +02003394
willy tarreau1f431b52006-05-21 14:46:15 +02003395 /* queue : current, max */
3396 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3397 "<td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
3398 px->totpend, px->nbpend_max);
willy tarreaucb406512006-05-18 00:52:35 +02003399
willy tarreau1f431b52006-05-21 14:46:15 +02003400 /* sessions : current, max, limit, cumul */
3401 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3402 "<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>",
3403 px->nbconn, px->nbconn_max, px->maxconn, px->cum_conn);
willy tarreaucb406512006-05-18 00:52:35 +02003404
willy tarreaue3b30652006-05-21 16:23:22 +02003405 /* errors : connect, response, security */
3406 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3407 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3408 px->failed_conns, px->failed_resp, px->failed_secu);
3409
3410 /* check failures : unique, fatal */
willy tarreau1f431b52006-05-21 14:46:15 +02003411 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3412 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3413 failed_checks, down_trans);
willy tarreaucb406512006-05-18 00:52:35 +02003414
willy tarreau1f431b52006-05-21 14:46:15 +02003415 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, "</table><p>\n");
3416
3417 if (buffer_write(rep, trash, msglen) != 0)
3418 return 0;
3419 msglen = 0;
3420
3421 s->data_ctx.stats.px_st = DATA_ST_INIT;
3422 next_proxy:
3423 s->data_ctx.stats.px = px->next;
willy tarreaucb406512006-05-18 00:52:35 +02003424 } /* proxy loop */
willy tarreaue0331262006-05-15 03:02:46 +02003425 /* here, we just have reached the sv == NULL and px == NULL */
3426 s->flags &= ~SN_SELF_GEN;
3427 return 1;
3428 }
3429 else {
3430 /* unknown data source */
3431 s->logs.status = 500;
3432 client_retnclose(s, s->proxy->errmsg.len500, s->proxy->errmsg.msg500);
3433 if (!(s->flags & SN_ERR_MASK))
3434 s->flags |= SN_ERR_PRXCOND;
3435 if (!(s->flags & SN_FINST_MASK))
3436 s->flags |= SN_FINST_R;
3437 s->flags &= SN_SELF_GEN;
3438 return 1;
3439 }
3440}
3441
3442
willy tarreau9fe663a2005-12-17 13:02:59 +01003443/*
3444 * send a log for the session when we have enough info about it
3445 */
3446void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003447 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01003448 struct proxy *p = s->proxy;
3449 int log;
3450 char *uri;
3451 char *pxid;
3452 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01003453 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01003454
3455 /* This is a first attempt at a better logging system.
3456 * For now, we rely on send_log() to provide the date, although it obviously
3457 * is the date of the log and not of the request, and most fields are not
3458 * computed.
3459 */
3460
willy tarreaua1598082005-12-17 13:08:06 +01003461 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01003462
willy tarreau8a86dbf2005-12-18 00:45:59 +01003463 if (s->cli_addr.ss_family == AF_INET)
3464 inet_ntop(AF_INET,
3465 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3466 pn, sizeof(pn));
3467 else
3468 inet_ntop(AF_INET6,
3469 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3470 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01003471
willy tarreauc1cae632005-12-17 14:12:23 +01003472 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01003473 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01003474 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01003475
willy tarreauc1cae632005-12-17 14:12:23 +01003476 tm = localtime(&s->logs.tv_accept.tv_sec);
3477 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01003478 char tmpline[MAX_SYSLOG_LEN], *h;
3479 int hdr;
3480
3481 h = tmpline;
3482 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
3483 *(h++) = ' ';
3484 *(h++) = '{';
3485 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
3486 if (hdr)
3487 *(h++) = '|';
3488 if (s->req_cap[hdr] != NULL)
3489 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
3490 }
3491 *(h++) = '}';
3492 }
3493
3494 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
3495 *(h++) = ' ';
3496 *(h++) = '{';
3497 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
3498 if (hdr)
3499 *(h++) = '|';
3500 if (s->rsp_cap[hdr] != NULL)
3501 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
3502 }
3503 *(h++) = '}';
3504 }
3505
3506 if (h < tmpline + sizeof(tmpline) - 4) {
3507 *(h++) = ' ';
3508 *(h++) = '"';
3509 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
3510 *(h++) = '"';
3511 }
3512 *h = '\0';
3513
willy tarreau5e69b162006-05-12 19:49:37 +02003514 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 +01003515 pn,
3516 (s->cli_addr.ss_family == AF_INET) ?
3517 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3518 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01003519 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3520 tm->tm_hour, tm->tm_min, tm->tm_sec,
3521 pxid, srv,
3522 s->logs.t_request,
willy tarreauf32f5242006-05-02 22:54:52 +02003523 (s->logs.t_queue >= 0) ? s->logs.t_queue - s->logs.t_request : -1,
3524 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreaua1598082005-12-17 13:08:06 +01003525 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003526 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3527 s->logs.status,
3528 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01003529 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
3530 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01003531 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
3532 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
3533 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
3534 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau5e69b162006-05-12 19:49:37 +02003535 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3536 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01003537 }
3538 else {
willy tarreau5f15c552006-05-13 18:37:04 +02003539 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 +01003540 pn,
3541 (s->cli_addr.ss_family == AF_INET) ?
3542 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3543 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01003544 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3545 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01003546 pxid, srv,
willy tarreau5f15c552006-05-13 18:37:04 +02003547 (s->logs.t_queue >= 0) ? s->logs.t_queue : -1,
3548 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003549 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3550 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01003551 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01003552 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreau5e69b162006-05-12 19:49:37 +02003553 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3554 s->logs.srv_queue_size, s->logs.prx_queue_size);
willy tarreaua1598082005-12-17 13:08:06 +01003555 }
3556
3557 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003558}
3559
willy tarreaue39cd132005-12-17 13:00:18 +01003560
3561/*
willy tarreau0f7af912005-12-17 12:21:26 +01003562 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01003563 * to an accept. It tries to accept as many connections as possible.
3564 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01003565 */
3566int event_accept(int fd) {
3567 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003568 struct session *s;
3569 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01003570 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01003571 int max_accept;
3572
3573 if (global.nbproc > 1)
3574 max_accept = 8; /* let other processes catch some connections too */
3575 else
3576 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003577
willy tarreauc2becdc2006-03-19 19:36:48 +01003578 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003579 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003580 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01003581
willy tarreaub1285d52005-12-18 01:20:14 +01003582 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
3583 switch (errno) {
3584 case EAGAIN:
3585 case EINTR:
3586 case ECONNABORTED:
3587 return 0; /* nothing more to accept */
3588 case ENFILE:
3589 send_log(p, LOG_EMERG,
3590 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
3591 p->id, maxfd);
3592 return 0;
3593 case EMFILE:
3594 send_log(p, LOG_EMERG,
3595 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
3596 p->id, maxfd);
3597 return 0;
3598 case ENOBUFS:
3599 case ENOMEM:
3600 send_log(p, LOG_EMERG,
3601 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
3602 p->id, maxfd);
3603 return 0;
3604 default:
3605 return 0;
3606 }
3607 }
willy tarreau0f7af912005-12-17 12:21:26 +01003608
willy tarreau5cbea6f2005-12-17 12:48:26 +01003609 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
3610 Alert("out of memory in event_accept().\n");
3611 FD_CLR(fd, StaticReadEvent);
3612 p->state = PR_STIDLE;
3613 close(cfd);
3614 return 0;
3615 }
willy tarreau0f7af912005-12-17 12:21:26 +01003616
willy tarreaub1285d52005-12-18 01:20:14 +01003617 /* if this session comes from a known monitoring system, we want to ignore
3618 * it as soon as possible, which means closing it immediately for TCP.
3619 */
3620 s->flags = 0;
3621 if (addr.ss_family == AF_INET &&
3622 p->mon_mask.s_addr &&
3623 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
3624 if (p->mode == PR_MODE_TCP) {
3625 close(cfd);
3626 pool_free(session, s);
3627 continue;
3628 }
3629 s->flags |= SN_MONITOR;
3630 }
3631
willy tarreau5cbea6f2005-12-17 12:48:26 +01003632 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3633 Alert("out of memory in event_accept().\n");
3634 FD_CLR(fd, StaticReadEvent);
3635 p->state = PR_STIDLE;
3636 close(cfd);
3637 pool_free(session, s);
3638 return 0;
3639 }
willy tarreau0f7af912005-12-17 12:21:26 +01003640
willy tarreau5cbea6f2005-12-17 12:48:26 +01003641 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01003642 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003643 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
3644 close(cfd);
3645 pool_free(task, t);
3646 pool_free(session, s);
3647 return 0;
3648 }
willy tarreau0f7af912005-12-17 12:21:26 +01003649
willy tarreau5cbea6f2005-12-17 12:48:26 +01003650 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
3651 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
3652 (char *) &one, sizeof(one)) == -1)) {
3653 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
3654 close(cfd);
3655 pool_free(task, t);
3656 pool_free(session, s);
3657 return 0;
3658 }
willy tarreau0f7af912005-12-17 12:21:26 +01003659
willy tarreaub952e1d2005-12-18 01:31:20 +01003660 if (p->options & PR_O_TCP_CLI_KA)
3661 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
3662
willy tarreau9fe663a2005-12-17 13:02:59 +01003663 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02003664 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
willy tarreau9fe663a2005-12-17 13:02:59 +01003665 t->state = TASK_IDLE;
3666 t->process = process_session;
3667 t->context = s;
3668
3669 s->task = t;
3670 s->proxy = p;
3671 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
3672 s->srv_state = SV_STIDLE;
3673 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01003674
willy tarreau9fe663a2005-12-17 13:02:59 +01003675 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
3676 s->cli_fd = cfd;
3677 s->srv_fd = -1;
willy tarreau9e138862006-05-14 23:06:28 +02003678 s->req_line.len = -1;
3679 s->auth_hdr.len = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003680 s->srv = NULL;
Willy TARREAU1a71cc12006-05-14 09:10:03 +02003681 s->pend_pos = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01003682 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01003683
willy tarreaub1285d52005-12-18 01:20:14 +01003684 if (s->flags & SN_MONITOR)
3685 s->logs.logwait = 0;
3686 else
3687 s->logs.logwait = p->to_log;
3688
willy tarreaua1598082005-12-17 13:08:06 +01003689 s->logs.tv_accept = now;
3690 s->logs.t_request = -1;
willy tarreauf32f5242006-05-02 22:54:52 +02003691 s->logs.t_queue = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003692 s->logs.t_connect = -1;
3693 s->logs.t_data = -1;
3694 s->logs.t_close = 0;
3695 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01003696 s->logs.cli_cookie = NULL;
3697 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01003698 s->logs.status = -1;
3699 s->logs.bytes = 0;
willy tarreau5e69b162006-05-12 19:49:37 +02003700 s->logs.prx_queue_size = 0; /* we get the number of pending conns before us */
3701 s->logs.srv_queue_size = 0; /* we will get this number soon */
willy tarreau9fe663a2005-12-17 13:02:59 +01003702
willy tarreaue0331262006-05-15 03:02:46 +02003703 s->data_source = DATA_SRC_NONE;
willy tarreaue0331262006-05-15 03:02:46 +02003704
willy tarreau2f6ba652005-12-17 13:57:42 +01003705 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02003706 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01003707
willy tarreau4302f492005-12-18 01:00:37 +01003708 if (p->nb_req_cap > 0) {
3709 if ((s->req_cap =
3710 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
3711 == NULL) { /* no memory */
3712 close(cfd); /* nothing can be done for this fd without memory */
3713 pool_free(task, t);
3714 pool_free(session, s);
3715 return 0;
3716 }
3717 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
3718 }
3719 else
3720 s->req_cap = NULL;
3721
3722 if (p->nb_rsp_cap > 0) {
3723 if ((s->rsp_cap =
3724 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
3725 == NULL) { /* no memory */
3726 if (s->req_cap != NULL)
3727 pool_free_to(p->req_cap_pool, s->req_cap);
3728 close(cfd); /* nothing can be done for this fd without memory */
3729 pool_free(task, t);
3730 pool_free(session, s);
3731 return 0;
3732 }
3733 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
3734 }
3735 else
3736 s->rsp_cap = NULL;
3737
willy tarreau5cbea6f2005-12-17 12:48:26 +01003738 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
3739 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003740 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003741 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01003742
willy tarreau8a86dbf2005-12-18 00:45:59 +01003743 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003744 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003745 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003746 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01003747
willy tarreau9fe663a2005-12-17 13:02:59 +01003748 if (p->to_log) {
3749 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01003750 if (s->logs.logwait & LW_CLIP)
3751 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01003752 sess_log(s);
3753 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01003754 else if (s->cli_addr.ss_family == AF_INET) {
3755 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
3756 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
3757 sn, sizeof(sn)) &&
3758 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3759 pn, sizeof(pn))) {
3760 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3761 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
3762 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
3763 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3764 }
3765 }
3766 else {
3767 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
3768 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
3769 sn, sizeof(sn)) &&
3770 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
3771 pn, sizeof(pn))) {
3772 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3773 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
3774 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
3775 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3776 }
3777 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003778 }
willy tarreau0f7af912005-12-17 12:21:26 +01003779
willy tarreau982249e2005-12-18 00:57:06 +01003780 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01003781 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003782 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01003783 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01003784 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003785 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003786 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01003787 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01003788
willy tarreau8a86dbf2005-12-18 00:45:59 +01003789 if (s->cli_addr.ss_family == AF_INET) {
3790 char pn[INET_ADDRSTRLEN];
3791 inet_ntop(AF_INET,
3792 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3793 pn, sizeof(pn));
3794
3795 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3796 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3797 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
3798 }
3799 else {
3800 char pn[INET6_ADDRSTRLEN];
3801 inet_ntop(AF_INET6,
3802 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3803 pn, sizeof(pn));
3804
3805 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3806 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3807 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3808 }
3809
willy tarreauef900ab2005-12-17 12:52:52 +01003810 write(1, trash, len);
3811 }
willy tarreau0f7af912005-12-17 12:21:26 +01003812
willy tarreau5cbea6f2005-12-17 12:48:26 +01003813 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003814 if (s->rsp_cap != NULL)
3815 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3816 if (s->req_cap != NULL)
3817 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003818 close(cfd); /* nothing can be done for this fd without memory */
3819 pool_free(task, t);
3820 pool_free(session, s);
3821 return 0;
3822 }
willy tarreau4302f492005-12-18 01:00:37 +01003823
willy tarreau5cbea6f2005-12-17 12:48:26 +01003824 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003825 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003826 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3827 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003828 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003829 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003830
willy tarreau5cbea6f2005-12-17 12:48:26 +01003831 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3832 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003833 if (s->rsp_cap != NULL)
3834 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3835 if (s->req_cap != NULL)
3836 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003837 close(cfd); /* nothing can be done for this fd without memory */
3838 pool_free(task, t);
3839 pool_free(session, s);
3840 return 0;
3841 }
3842 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003843 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003844 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 +01003845
willy tarreau5cbea6f2005-12-17 12:48:26 +01003846 fdtab[cfd].read = &event_cli_read;
3847 fdtab[cfd].write = &event_cli_write;
3848 fdtab[cfd].owner = t;
3849 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003850
willy tarreaub1285d52005-12-18 01:20:14 +01003851 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3852 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3853 /* Either we got a request from a monitoring system on an HTTP instance,
3854 * or we're in health check mode with the 'httpchk' option enabled. In
3855 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3856 */
3857 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3858 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3859 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003860 }
3861 else {
3862 FD_SET(cfd, StaticReadEvent);
3863 }
3864
willy tarreaub952e1d2005-12-18 01:31:20 +01003865#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3866 if (PrevReadEvent) {
3867 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3868 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3869 }
3870#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003871 fd_insert(cfd);
3872
3873 tv_eternity(&s->cnexpire);
3874 tv_eternity(&s->srexpire);
3875 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003876 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003877 tv_eternity(&s->cwexpire);
3878
willy tarreaub1285d52005-12-18 01:20:14 +01003879 if (s->proxy->clitimeout) {
3880 if (FD_ISSET(cfd, StaticReadEvent))
3881 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3882 if (FD_ISSET(cfd, StaticWriteEvent))
3883 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3884 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003885
willy tarreaub1285d52005-12-18 01:20:14 +01003886 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003887
3888 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003889
3890 if (p->mode != PR_MODE_HEALTH)
3891 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003892
3893 p->nbconn++;
willy tarreaucb406512006-05-18 00:52:35 +02003894 if (p->nbconn > p->nbconn_max)
3895 p->nbconn_max = p->nbconn;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003896 actconn++;
3897 totalconn++;
3898
willy tarreaub952e1d2005-12-18 01:31:20 +01003899 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003900 } /* end of while (p->nbconn < p->maxconn) */
3901 return 0;
3902}
willy tarreau0f7af912005-12-17 12:21:26 +01003903
willy tarreau0f7af912005-12-17 12:21:26 +01003904
willy tarreau5cbea6f2005-12-17 12:48:26 +01003905/*
3906 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003907 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3908 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003909 * or -1 if an error occured.
3910 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003911int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003912 struct task *t = fdtab[fd].owner;
3913 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003914 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003915 socklen_t lskerr = sizeof(skerr);
3916
willy tarreau05be12b2006-03-19 19:35:00 +01003917 skerr = 1;
3918 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3919 || (skerr != 0)) {
3920 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003921 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003922 fdtab[fd].state = FD_STERROR;
3923 FD_CLR(fd, StaticWriteEvent);
3924 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003925 else if (s->result != -1) {
3926 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003927 if (s->proxy->options & PR_O_HTTP_CHK) {
3928 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003929 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003930 * so we'll send the request, and won't wake the checker up now.
3931 */
3932#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003933 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003934#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003935 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003936#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003937 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003938 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3939 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3940 return 0;
3941 }
willy tarreau05be12b2006-03-19 19:35:00 +01003942 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003943 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003944 FD_CLR(fd, StaticWriteEvent);
3945 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003946 }
3947 else {
3948 /* good TCP connection is enough */
3949 s->result = 1;
3950 }
3951 }
3952
3953 task_wakeup(&rq, t);
3954 return 0;
3955}
3956
willy tarreau0f7af912005-12-17 12:21:26 +01003957
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003958/*
3959 * This function is used only for server health-checks. It handles
3960 * the server's reply to an HTTP request. It returns 1 if the server replies
3961 * 2xx or 3xx (valid responses), or -1 in other cases.
3962 */
3963int event_srv_chk_r(int fd) {
3964 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003965 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003966 struct task *t = fdtab[fd].owner;
3967 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003968 int skerr;
3969 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003970
willy tarreaua4a583a2005-12-18 01:39:19 +01003971 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003972
willy tarreau05be12b2006-03-19 19:35:00 +01003973 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3974 if (!skerr) {
3975#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003976 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003977#else
willy tarreau05be12b2006-03-19 19:35:00 +01003978 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3979 * but the connection was closed on the remote end. Fortunately, recv still
3980 * works correctly and we don't need to do the getsockopt() on linux.
3981 */
3982 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003983#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003984
3985 if ((len >= sizeof("HTTP/1.0 000")) &&
3986 !memcmp(reply, "HTTP/1.", 7) &&
3987 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3988 result = 1;
3989 }
3990
3991 if (result == -1)
3992 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003993
3994 if (s->result != -1)
3995 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003996
3997 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003998 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003999 return 0;
4000}
4001
4002
4003/*
4004 * this function writes the string <str> at position <pos> which must be in buffer <b>,
4005 * and moves <end> just after the end of <str>.
4006 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
4007 * the shift value (positive or negative) is returned.
4008 * If there's no space left, the move is not done.
4009 *
4010 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004011int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01004012 int delta;
4013 int len;
4014
4015 len = strlen(str);
4016 delta = len - (end - pos);
4017
4018 if (delta + b->r >= b->data + BUFSIZE)
4019 return 0; /* no space left */
4020
4021 /* first, protect the end of the buffer */
4022 memmove(end + delta, end, b->data + b->l - end);
4023
4024 /* now, copy str over pos */
4025 memcpy(pos, str,len);
4026
willy tarreau5cbea6f2005-12-17 12:48:26 +01004027 /* we only move data after the displaced zone */
4028 if (b->r > pos) b->r += delta;
4029 if (b->w > pos) b->w += delta;
4030 if (b->h > pos) b->h += delta;
4031 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01004032 b->l += delta;
4033
4034 return delta;
4035}
4036
willy tarreau8337c6b2005-12-17 13:41:01 +01004037/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01004038 * len is 0.
4039 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004040int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01004041 int delta;
4042
4043 delta = len - (end - pos);
4044
4045 if (delta + b->r >= b->data + BUFSIZE)
4046 return 0; /* no space left */
4047
Willy TARREAUe78ae262006-01-08 01:24:12 +01004048 if (b->data + b->l < end)
4049 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
4050 return 0;
4051
willy tarreau0f7af912005-12-17 12:21:26 +01004052 /* first, protect the end of the buffer */
4053 memmove(end + delta, end, b->data + b->l - end);
4054
4055 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01004056 if (len)
4057 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01004058
willy tarreau5cbea6f2005-12-17 12:48:26 +01004059 /* we only move data after the displaced zone */
4060 if (b->r > pos) b->r += delta;
4061 if (b->w > pos) b->w += delta;
4062 if (b->h > pos) b->h += delta;
4063 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01004064 b->l += delta;
4065
4066 return delta;
4067}
4068
4069
4070int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
4071 char *old_dst = dst;
4072
4073 while (*str) {
4074 if (*str == '\\') {
4075 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01004076 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004077 int len, num;
4078
4079 num = *str - '0';
4080 str++;
4081
willy tarreau8a86dbf2005-12-18 00:45:59 +01004082 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01004083 len = matches[num].rm_eo - matches[num].rm_so;
4084 memcpy(dst, src + matches[num].rm_so, len);
4085 dst += len;
4086 }
4087
4088 }
4089 else if (*str == 'x') {
4090 unsigned char hex1, hex2;
4091 str++;
4092
willy tarreauc1f47532005-12-18 01:08:26 +01004093 hex1 = toupper(*str++) - '0';
4094 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01004095
4096 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
4097 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
4098 *dst++ = (hex1<<4) + hex2;
4099 }
4100 else
4101 *dst++ = *str++;
4102 }
4103 else
4104 *dst++ = *str++;
4105 }
4106 *dst = 0;
4107 return dst - old_dst;
4108}
4109
willy tarreauc1f47532005-12-18 01:08:26 +01004110static int ishex(char s)
4111{
4112 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
4113}
4114
4115/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
4116char *check_replace_string(char *str)
4117{
4118 char *err = NULL;
4119 while (*str) {
4120 if (*str == '\\') {
4121 err = str; /* in case of a backslash, we return the pointer to it */
4122 str++;
4123 if (!*str)
4124 return err;
4125 else if (isdigit((int)*str))
4126 err = NULL;
4127 else if (*str == 'x') {
4128 str++;
4129 if (!ishex(*str))
4130 return err;
4131 str++;
4132 if (!ishex(*str))
4133 return err;
4134 err = NULL;
4135 }
4136 else {
4137 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
4138 err = NULL;
4139 }
4140 }
4141 str++;
4142 }
4143 return err;
4144}
4145
willy tarreau0f7af912005-12-17 12:21:26 +01004146/*
4147 * manages the client FSM and its socket. BTW, it also tries to handle the
4148 * cookie. It returns 1 if a state has changed (and a resync may be needed),
4149 * 0 else.
4150 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004151int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004152 int s = t->srv_state;
4153 int c = t->cli_state;
4154 struct buffer *req = t->req;
4155 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004156 int method_checked = 0;
4157 appsess *asession_temp = NULL;
4158 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01004159
willy tarreau750a4722005-12-17 13:21:24 +01004160#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01004161 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
4162 cli_stnames[c], srv_stnames[s],
4163 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4164 t->crexpire.tv_sec, t->crexpire.tv_usec,
4165 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01004166#endif
willy tarreau0f7af912005-12-17 12:21:26 +01004167 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4168 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4169 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4170 //);
4171 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004172 /* now parse the partial (or complete) headers */
4173 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
4174 char *ptr;
4175 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01004176 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01004177
willy tarreau5cbea6f2005-12-17 12:48:26 +01004178 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01004179
willy tarreau0f7af912005-12-17 12:21:26 +01004180 /* look for the end of the current header */
4181 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
4182 ptr++;
4183
willy tarreau5cbea6f2005-12-17 12:48:26 +01004184 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004185 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02004186
4187 /*
4188 * first, let's check that it's not a leading empty line, in
4189 * which case we'll ignore and remove it (according to RFC2616).
4190 */
4191 if (req->h == req->data) {
4192 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4193 if (ptr > req->r - 2) {
4194 /* this is a partial header, let's wait for more to come */
4195 req->lr = ptr;
4196 break;
4197 }
4198
4199 /* now we know that *ptr is either \r or \n,
4200 * and that there are at least 1 char after it.
4201 */
4202 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4203 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4204 else
4205 req->lr = ptr + 2; /* \r\n or \n\r */
4206 /* ignore empty leading lines */
4207 buffer_replace2(req, req->h, req->lr, NULL, 0);
4208 req->h = req->lr;
4209 continue;
4210 }
4211
willy tarreau5cbea6f2005-12-17 12:48:26 +01004212 /* we can only get here after an end of headers */
4213 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01004214
willy tarreaue39cd132005-12-17 13:00:18 +01004215 if (t->flags & SN_CLDENY) {
4216 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01004217 t->logs.status = 403;
willy tarreau47ee7ad2006-05-18 01:25:36 +02004218 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now); /* let's log the request time */
willy tarreau8337c6b2005-12-17 13:41:01 +01004219 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01004220 if (!(t->flags & SN_ERR_MASK))
4221 t->flags |= SN_ERR_PRXCOND;
4222 if (!(t->flags & SN_FINST_MASK))
4223 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004224 return 1;
4225 }
4226
willy tarreau9e138862006-05-14 23:06:28 +02004227 /* Right now, we know that we have processed the entire headers
4228 * and that unwanted requests have been filtered out. We can do
4229 * whatever we want.
4230 */
4231
willy tarreau9e138862006-05-14 23:06:28 +02004232 if (t->proxy->uri_auth != NULL
4233 && t->req_line.len >= t->proxy->uri_auth->uri_len + 4) { /* +4 for "GET /" */
4234 if (!memcmp(t->req_line.str + 4,
4235 t->proxy->uri_auth->uri_prefix, t->proxy->uri_auth->uri_len)
4236 && !memcmp(t->req_line.str, "GET ", 4)) {
4237 struct user_auth *user;
4238 int authenticated;
4239
4240 /* we are in front of a interceptable URI. Let's check
4241 * if there's an authentication and if it's valid.
4242 */
4243 user = t->proxy->uri_auth->users;
4244 if (!user) {
4245 /* no user auth required, it's OK */
4246 authenticated = 1;
4247 } else {
4248 authenticated = 0;
4249
4250 /* a user list is defined, we have to check.
4251 * skip 21 chars for "Authorization: Basic ".
4252 */
4253 if (t->auth_hdr.len < 21 || memcmp(t->auth_hdr.str + 14, " Basic ", 7))
4254 user = NULL;
4255
4256 while (user) {
4257 if ((t->auth_hdr.len == user->user_len + 21)
4258 && !memcmp(t->auth_hdr.str+21, user->user_pwd, user->user_len)) {
4259 authenticated = 1;
4260 break;
4261 }
4262 user = user->next;
willy tarreau9e138862006-05-14 23:06:28 +02004263 }
4264 }
4265
4266 if (!authenticated) {
4267 int msglen;
4268
4269 /* no need to go further */
4270
4271 msglen = sprintf(trash, HTTP_401_fmt, t->proxy->uri_auth->auth_realm);
4272 t->logs.status = 401;
4273 client_retnclose(t, msglen, trash);
4274 if (!(t->flags & SN_ERR_MASK))
4275 t->flags |= SN_ERR_PRXCOND;
4276 if (!(t->flags & SN_FINST_MASK))
4277 t->flags |= SN_FINST_R;
4278 return 1;
4279 }
4280
willy tarreaue0331262006-05-15 03:02:46 +02004281 t->cli_state = CL_STSHUTR;
willy tarreau950609c2006-05-18 01:23:51 +02004282 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
4283 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreaue0331262006-05-15 03:02:46 +02004284 t->data_source = DATA_SRC_STATS;
willy tarreau1f431b52006-05-21 14:46:15 +02004285 t->data_state = DATA_ST_INIT;
willy tarreaue0331262006-05-15 03:02:46 +02004286 produce_content(t);
4287 return 1;
willy tarreau9e138862006-05-14 23:06:28 +02004288 }
4289 }
4290
4291
willy tarreau5cbea6f2005-12-17 12:48:26 +01004292 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004293 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
4294 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004295 }
willy tarreau0f7af912005-12-17 12:21:26 +01004296
willy tarreau9fe663a2005-12-17 13:02:59 +01004297 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01004298 if (t->cli_addr.ss_family == AF_INET) {
4299 unsigned char *pn;
4300 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
4301 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
4302 pn[0], pn[1], pn[2], pn[3]);
4303 buffer_replace2(req, req->h, req->h, trash, len);
4304 }
4305 else if (t->cli_addr.ss_family == AF_INET6) {
4306 char pn[INET6_ADDRSTRLEN];
4307 inet_ntop(AF_INET6,
4308 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
4309 pn, sizeof(pn));
4310 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
4311 buffer_replace2(req, req->h, req->h, trash, len);
4312 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004313 }
4314
willy tarreau25c4ea52005-12-18 00:49:49 +01004315 /* add a "connection: close" line if needed */
4316 if (t->proxy->options & PR_O_HTTP_CLOSE)
4317 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
4318
willy tarreau982249e2005-12-18 00:57:06 +01004319 if (!memcmp(req->data, "POST ", 5)) {
4320 /* this is a POST request, which is not cacheable by default */
4321 t->flags |= SN_POST;
4322 }
willy tarreaucd878942005-12-17 13:27:43 +01004323
willy tarreau5cbea6f2005-12-17 12:48:26 +01004324 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004325 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01004326
willy tarreau750a4722005-12-17 13:21:24 +01004327 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004328 /* FIXME: we'll set the client in a wait state while we try to
4329 * connect to the server. Is this really needed ? wouldn't it be
willy tarreau0889c962006-04-24 14:36:48 +02004330 * better to release the maximum of system buffers instead ?
4331 * The solution is to enable the FD but set its time-out to
4332 * eternity as long as the server-side does not enable data xfer.
4333 * CL_STDATA also has to take care of this, which is done below.
4334 */
willy tarreauef900ab2005-12-17 12:52:52 +01004335 //FD_CLR(t->cli_fd, StaticReadEvent);
4336 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01004337
4338 /* FIXME: if we break here (as up to 1.1.23), having the client
4339 * shutdown its connection can lead to an abort further.
4340 * it's better to either return 1 or even jump directly to the
4341 * data state which will save one schedule.
4342 */
4343 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01004344
4345 if (!t->proxy->clitimeout ||
4346 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4347 /* If the client has no timeout, or if the server is not ready yet,
4348 * and we know for sure that it can expire, then it's cleaner to
4349 * disable the timeout on the client side so that too low values
4350 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01004351 *
4352 * FIXME-20050705: the server needs a way to re-enable this time-out
4353 * when it switches its state, otherwise a client can stay connected
4354 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01004355 */
4356 tv_eternity(&t->crexpire);
4357
willy tarreau197e8ec2005-12-17 14:10:59 +01004358 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004359 }
willy tarreau0f7af912005-12-17 12:21:26 +01004360
Willy TARREAU13032e72006-03-12 17:31:45 +01004361 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4362 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004363 /* this is a partial header, let's wait for more to come */
4364 req->lr = ptr;
4365 break;
4366 }
willy tarreau0f7af912005-12-17 12:21:26 +01004367
willy tarreau5cbea6f2005-12-17 12:48:26 +01004368 /* now we know that *ptr is either \r or \n,
4369 * and that there are at least 1 char after it.
4370 */
4371 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4372 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4373 else
4374 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01004375
willy tarreau5cbea6f2005-12-17 12:48:26 +01004376 /*
4377 * now we know that we have a full header ; we can do whatever
4378 * we want with these pointers :
4379 * req->h = beginning of header
4380 * ptr = end of header (first \r or \n)
4381 * req->lr = beginning of next line (next rep->h)
4382 * req->r = end of data (not used at this stage)
4383 */
willy tarreau0f7af912005-12-17 12:21:26 +01004384
willy tarreau12350152005-12-18 01:03:27 +01004385 if (!method_checked && (t->proxy->appsession_name != NULL) &&
4386 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
4387 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
4388
4389 /* skip ; */
4390 request_line++;
4391
4392 /* look if we have a jsessionid */
4393
4394 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
4395
4396 /* skip jsessionid= */
4397 request_line += t->proxy->appsession_name_len + 1;
4398
4399 /* First try if we allready have an appsession */
4400 asession_temp = &local_asession;
4401
4402 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4403 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
4404 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
4405 return 0;
4406 }
4407
4408 /* Copy the sessionid */
4409 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
4410 asession_temp->sessid[t->proxy->appsession_len] = 0;
4411 asession_temp->serverid = NULL;
4412
4413 /* only do insert, if lookup fails */
4414 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
4415 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4416 Alert("Not enough memory process_cli():asession:calloc().\n");
4417 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4418 return 0;
4419 }
4420 asession_temp->sessid = local_asession.sessid;
4421 asession_temp->serverid = local_asession.serverid;
4422 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004423 } /* end if (chtbl_lookup()) */
4424 else {
willy tarreau12350152005-12-18 01:03:27 +01004425 /*free wasted memory;*/
4426 pool_free_to(apools.sessid, local_asession.sessid);
4427 }
4428
4429 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4430 asession_temp->request_count++;
4431
4432#if defined(DEBUG_HASH)
4433 print_table(&(t->proxy->htbl_proxy));
4434#endif
4435
4436 if (asession_temp->serverid == NULL) {
4437 Alert("Found Application Session without matching server.\n");
4438 } else {
4439 struct server *srv = t->proxy->srv;
4440 while (srv) {
4441 if (strcmp(srv->id, asession_temp->serverid) == 0) {
4442 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4443 /* we found the server and it's usable */
4444 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004445 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004446 t->srv = srv;
4447 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01004448 } else {
willy tarreau12350152005-12-18 01:03:27 +01004449 t->flags &= ~SN_CK_MASK;
4450 t->flags |= SN_CK_DOWN;
4451 }
willy tarreaub952e1d2005-12-18 01:31:20 +01004452 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01004453 srv = srv->next;
4454 }/* end while(srv) */
4455 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01004456 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01004457 else {
4458 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
4459 }
willy tarreau598da412005-12-18 01:07:29 +01004460 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01004461 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01004462 else{
4463 //printf("No Methode-Header with Session-String\n");
4464 }
4465
willy tarreau8337c6b2005-12-17 13:41:01 +01004466 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004467 /* we have a complete HTTP request that we must log */
4468 int urilen;
4469
willy tarreaua1598082005-12-17 13:08:06 +01004470 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004471 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01004472 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01004473 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01004474 if (!(t->flags & SN_ERR_MASK))
4475 t->flags |= SN_ERR_PRXCOND;
4476 if (!(t->flags & SN_FINST_MASK))
4477 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01004478 return 1;
4479 }
4480
4481 urilen = ptr - req->h;
4482 if (urilen >= REQURI_LEN)
4483 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01004484 memcpy(t->logs.uri, req->h, urilen);
4485 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004486
willy tarreaua1598082005-12-17 13:08:06 +01004487 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01004488 sess_log(t);
4489 }
willy tarreau4302f492005-12-18 01:00:37 +01004490 else if (t->logs.logwait & LW_REQHDR) {
4491 struct cap_hdr *h;
4492 int len;
4493 for (h = t->proxy->req_cap; h; h = h->next) {
4494 if ((h->namelen + 2 <= ptr - req->h) &&
4495 (req->h[h->namelen] == ':') &&
4496 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
4497
4498 if (t->req_cap[h->index] == NULL)
4499 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4500
4501 len = ptr - (req->h + h->namelen + 2);
4502 if (len > h->len)
4503 len = h->len;
4504
4505 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
4506 t->req_cap[h->index][len]=0;
4507 }
4508 }
4509
4510 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004511
willy tarreau5cbea6f2005-12-17 12:48:26 +01004512 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004513
willy tarreau982249e2005-12-18 00:57:06 +01004514 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004515 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004516 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 +01004517 max = ptr - req->h;
4518 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004519 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004520 trash[len++] = '\n';
4521 write(1, trash, len);
4522 }
willy tarreau0f7af912005-12-17 12:21:26 +01004523
willy tarreau25c4ea52005-12-18 00:49:49 +01004524
4525 /* remove "connection: " if needed */
4526 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4527 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
4528 delete_header = 1;
4529 }
4530
willy tarreau5cbea6f2005-12-17 12:48:26 +01004531 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004532 if (!delete_header && t->proxy->req_exp != NULL
4533 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004534 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004535 char term;
4536
4537 term = *ptr;
4538 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004539 exp = t->proxy->req_exp;
4540 do {
4541 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
4542 switch (exp->action) {
4543 case ACT_ALLOW:
4544 if (!(t->flags & SN_CLDENY))
4545 t->flags |= SN_CLALLOW;
4546 break;
4547 case ACT_REPLACE:
4548 if (!(t->flags & SN_CLDENY)) {
4549 int len = exp_replace(trash, req->h, exp->replace, pmatch);
4550 ptr += buffer_replace2(req, req->h, ptr, trash, len);
4551 }
4552 break;
4553 case ACT_REMOVE:
4554 if (!(t->flags & SN_CLDENY))
4555 delete_header = 1;
4556 break;
4557 case ACT_DENY:
4558 if (!(t->flags & SN_CLALLOW))
4559 t->flags |= SN_CLDENY;
4560 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004561 case ACT_PASS: /* we simply don't deny this one */
4562 break;
willy tarreau0f7af912005-12-17 12:21:26 +01004563 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004564 break;
willy tarreau0f7af912005-12-17 12:21:26 +01004565 }
willy tarreaue39cd132005-12-17 13:00:18 +01004566 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004567 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01004568 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004569
willy tarreau240afa62005-12-17 13:14:35 +01004570 /* Now look for cookies. Conforming to RFC2109, we have to support
4571 * attributes whose name begin with a '$', and associate them with
4572 * the right cookie, if we want to delete this cookie.
4573 * So there are 3 cases for each cookie read :
4574 * 1) it's a special attribute, beginning with a '$' : ignore it.
4575 * 2) it's a server id cookie that we *MAY* want to delete : save
4576 * some pointers on it (last semi-colon, beginning of cookie...)
4577 * 3) it's an application cookie : we *MAY* have to delete a previous
4578 * "special" cookie.
4579 * At the end of loop, if a "special" cookie remains, we may have to
4580 * remove it. If no application cookie persists in the header, we
4581 * *MUST* delete it
4582 */
willy tarreau12350152005-12-18 01:03:27 +01004583 if (!delete_header &&
4584 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01004585 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01004586 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004587 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01004588 char *del_colon, *del_cookie, *colon;
4589 int app_cookies;
4590
willy tarreau5cbea6f2005-12-17 12:48:26 +01004591 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01004592 colon = p1;
4593 /* del_cookie == NULL => nothing to be deleted */
4594 del_colon = del_cookie = NULL;
4595 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004596
4597 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01004598 /* skip spaces and colons, but keep an eye on these ones */
4599 while (p1 < ptr) {
4600 if (*p1 == ';' || *p1 == ',')
4601 colon = p1;
4602 else if (!isspace((int)*p1))
4603 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004604 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01004605 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004606
4607 if (p1 == ptr)
4608 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004609
4610 /* p1 is at the beginning of the cookie name */
4611 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01004612 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004613 p2++;
4614
4615 if (p2 == ptr)
4616 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004617
4618 p3 = p2 + 1; /* skips the '=' sign */
4619 if (p3 == ptr)
4620 break;
4621
willy tarreau240afa62005-12-17 13:14:35 +01004622 p4 = p3;
4623 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004624 p4++;
4625
4626 /* here, we have the cookie name between p1 and p2,
4627 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01004628 * we can process it :
4629 *
4630 * Cookie: NAME=VALUE;
4631 * | || || |
4632 * | || || +--> p4
4633 * | || |+-------> p3
4634 * | || +--------> p2
4635 * | |+------------> p1
4636 * | +-------------> colon
4637 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01004638 */
4639
willy tarreau240afa62005-12-17 13:14:35 +01004640 if (*p1 == '$') {
4641 /* skip this one */
4642 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004643 else {
4644 /* first, let's see if we want to capture it */
4645 if (t->proxy->capture_name != NULL &&
4646 t->logs.cli_cookie == NULL &&
4647 (p4 - p1 >= t->proxy->capture_namelen) &&
4648 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4649 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004650
willy tarreau8337c6b2005-12-17 13:41:01 +01004651 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4652 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01004653 } else {
4654 if (log_len > t->proxy->capture_len)
4655 log_len = t->proxy->capture_len;
4656 memcpy(t->logs.cli_cookie, p1, log_len);
4657 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01004658 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004659 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004660
4661 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4662 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
4663 /* Cool... it's the right one */
4664 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01004665 char *delim;
4666
4667 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4668 * have the server ID betweek p3 and delim, and the original cookie between
4669 * delim+1 and p4. Otherwise, delim==p4 :
4670 *
4671 * Cookie: NAME=SRV~VALUE;
4672 * | || || | |
4673 * | || || | +--> p4
4674 * | || || +--------> delim
4675 * | || |+-----------> p3
4676 * | || +------------> p2
4677 * | |+----------------> p1
4678 * | +-----------------> colon
4679 * +------------------------> req->h
4680 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004681
willy tarreau0174f312005-12-18 01:02:42 +01004682 if (t->proxy->options & PR_O_COOK_PFX) {
4683 for (delim = p3; delim < p4; delim++)
4684 if (*delim == COOKIE_DELIM)
4685 break;
4686 }
4687 else
4688 delim = p4;
4689
4690
4691 /* Here, we'll look for the first running server which supports the cookie.
4692 * This allows to share a same cookie between several servers, for example
4693 * to dedicate backup servers to specific servers only.
willy tarreau422bb2e2006-05-10 04:27:21 +02004694 * However, to prevent clients from sticking to cookie-less backup server
4695 * when they have incidentely learned an empty cookie, we simply ignore
4696 * empty cookies and mark them as invalid.
willy tarreau0174f312005-12-18 01:02:42 +01004697 */
willy tarreau422bb2e2006-05-10 04:27:21 +02004698 if (delim == p3)
4699 srv = NULL;
4700
willy tarreau0174f312005-12-18 01:02:42 +01004701 while (srv) {
4702 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
4703 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4704 /* we found the server and it's usable */
4705 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004706 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau0174f312005-12-18 01:02:42 +01004707 t->srv = srv;
4708 break;
willy tarreau12350152005-12-18 01:03:27 +01004709 } else {
willy tarreau0174f312005-12-18 01:02:42 +01004710 /* we found a server, but it's down */
4711 t->flags &= ~SN_CK_MASK;
4712 t->flags |= SN_CK_DOWN;
4713 }
4714 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004715 srv = srv->next;
4716 }
4717
willy tarreau0174f312005-12-18 01:02:42 +01004718 if (!srv && !(t->flags & SN_CK_DOWN)) {
4719 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01004720 t->flags &= ~SN_CK_MASK;
4721 t->flags |= SN_CK_INVALID;
4722 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004723
willy tarreau0174f312005-12-18 01:02:42 +01004724 /* depending on the cookie mode, we may have to either :
4725 * - delete the complete cookie if we're in insert+indirect mode, so that
4726 * the server never sees it ;
4727 * - remove the server id from the cookie value, and tag the cookie as an
4728 * application cookie so that it does not get accidentely removed later,
4729 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01004730 */
willy tarreau0174f312005-12-18 01:02:42 +01004731 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
4732 buffer_replace2(req, p3, delim + 1, NULL, 0);
4733 p4 -= (delim + 1 - p3);
4734 ptr -= (delim + 1 - p3);
4735 del_cookie = del_colon = NULL;
4736 app_cookies++; /* protect the header from deletion */
4737 }
4738 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01004739 (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 +01004740 del_cookie = p1;
4741 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01004742 }
willy tarreau12350152005-12-18 01:03:27 +01004743 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01004744 /* now we know that we must keep this cookie since it's
4745 * not ours. But if we wanted to delete our cookie
4746 * earlier, we cannot remove the complete header, but we
4747 * can remove the previous block itself.
4748 */
4749 app_cookies++;
4750
4751 if (del_cookie != NULL) {
4752 buffer_replace2(req, del_cookie, p1, NULL, 0);
4753 p4 -= (p1 - del_cookie);
4754 ptr -= (p1 - del_cookie);
4755 del_cookie = del_colon = NULL;
4756 }
willy tarreau240afa62005-12-17 13:14:35 +01004757 }
willy tarreau12350152005-12-18 01:03:27 +01004758
4759 if ((t->proxy->appsession_name != NULL) &&
4760 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4761 /* first, let's see if the cookie is our appcookie*/
4762
4763 /* Cool... it's the right one */
4764
4765 asession_temp = &local_asession;
4766
4767 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4768 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4769 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4770 return 0;
4771 }
4772
4773 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4774 asession_temp->sessid[t->proxy->appsession_len] = 0;
4775 asession_temp->serverid = NULL;
4776
4777 /* only do insert, if lookup fails */
4778 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4779 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4780 Alert("Not enough memory process_cli():asession:calloc().\n");
4781 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4782 return 0;
4783 }
4784
4785 asession_temp->sessid = local_asession.sessid;
4786 asession_temp->serverid = local_asession.serverid;
4787 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4788 }
4789 else{
4790 /* free wasted memory */
4791 pool_free_to(apools.sessid, local_asession.sessid);
4792 }
4793
4794 if (asession_temp->serverid == NULL) {
4795 Alert("Found Application Session without matching server.\n");
4796 } else {
4797 struct server *srv = t->proxy->srv;
4798 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01004799 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01004800 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4801 /* we found the server and it's usable */
4802 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004803 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004804 t->srv = srv;
4805 break;
4806 } else {
4807 t->flags &= ~SN_CK_MASK;
4808 t->flags |= SN_CK_DOWN;
4809 }
4810 }
4811 srv = srv->next;
4812 }/* end while(srv) */
4813 }/* end else if server == NULL */
4814
4815 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01004816 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004817 }
willy tarreau240afa62005-12-17 13:14:35 +01004818
willy tarreau5cbea6f2005-12-17 12:48:26 +01004819 /* we'll have to look for another cookie ... */
4820 p1 = p4;
4821 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01004822
4823 /* There's no more cookie on this line.
4824 * We may have marked the last one(s) for deletion.
4825 * We must do this now in two ways :
4826 * - if there is no app cookie, we simply delete the header ;
4827 * - if there are app cookies, we must delete the end of the
4828 * string properly, including the colon/semi-colon before
4829 * the cookie name.
4830 */
4831 if (del_cookie != NULL) {
4832 if (app_cookies) {
4833 buffer_replace2(req, del_colon, ptr, NULL, 0);
4834 /* WARNING! <ptr> becomes invalid for now. If some code
4835 * below needs to rely on it before the end of the global
4836 * header loop, we need to correct it with this code :
willy tarreau240afa62005-12-17 13:14:35 +01004837 */
willy tarreau9e138862006-05-14 23:06:28 +02004838 ptr = del_colon;
willy tarreau240afa62005-12-17 13:14:35 +01004839 }
4840 else
4841 delete_header = 1;
4842 }
4843 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004844
4845 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004846 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01004847 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau9e138862006-05-14 23:06:28 +02004848 /* WARNING: ptr is not valid anymore, since the header may have
4849 * been deleted or truncated ! */
4850 } else {
4851 /* try to catch the first line as the request */
4852 if (t->req_line.len < 0) {
4853 t->req_line.str = req->h;
4854 t->req_line.len = ptr - req->h;
4855 }
4856
4857 /* We might also need the 'Authorization: ' header */
4858 if (t->auth_hdr.len < 0 &&
4859 t->proxy->uri_auth != NULL &&
4860 ptr > req->h + 15 &&
4861 !strncasecmp("Authorization: ", req->h, 15)) {
4862 t->auth_hdr.str = req->h;
4863 t->auth_hdr.len = ptr - req->h;
4864 }
willy tarreau0f7af912005-12-17 12:21:26 +01004865 }
willy tarreau240afa62005-12-17 13:14:35 +01004866
willy tarreau5cbea6f2005-12-17 12:48:26 +01004867 req->h = req->lr;
4868 } /* while (req->lr < req->r) */
4869
4870 /* end of header processing (even if incomplete) */
4871
willy tarreauef900ab2005-12-17 12:52:52 +01004872 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4873 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4874 * full. We cannot loop here since event_cli_read will disable it only if
4875 * req->l == rlim-data
4876 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004877 FD_SET(t->cli_fd, StaticReadEvent);
4878 if (t->proxy->clitimeout)
4879 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4880 else
4881 tv_eternity(&t->crexpire);
4882 }
4883
willy tarreaue39cd132005-12-17 13:00:18 +01004884 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01004885 * won't be able to free more later, so the session will never terminate.
4886 */
willy tarreaue39cd132005-12-17 13:00:18 +01004887 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01004888 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01004889 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01004890 if (!(t->flags & SN_ERR_MASK))
4891 t->flags |= SN_ERR_PRXCOND;
4892 if (!(t->flags & SN_FINST_MASK))
4893 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004894 return 1;
4895 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004896 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004897 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004898 tv_eternity(&t->crexpire);
4899 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004900 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004901 if (!(t->flags & SN_ERR_MASK))
4902 t->flags |= SN_ERR_CLICL;
4903 if (!(t->flags & SN_FINST_MASK))
4904 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004905 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004906 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004907 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4908
4909 /* read timeout : give up with an error message.
4910 */
4911 t->logs.status = 408;
4912 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004913 if (!(t->flags & SN_ERR_MASK))
4914 t->flags |= SN_ERR_CLITO;
4915 if (!(t->flags & SN_FINST_MASK))
4916 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004917 return 1;
4918 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004919
4920 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004921 }
4922 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004923 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004924 /* FIXME: this error handling is partly buggy because we always report
4925 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4926 * or HEADER phase. BTW, it's not logical to expire the client while
4927 * we're waiting for the server to connect.
4928 */
willy tarreau0f7af912005-12-17 12:21:26 +01004929 /* read or write error */
4930 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004931 tv_eternity(&t->crexpire);
4932 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004933 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004934 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004935 if (!(t->flags & SN_ERR_MASK))
4936 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004937 if (!(t->flags & SN_FINST_MASK)) {
4938 if (t->pend_pos)
4939 t->flags |= SN_FINST_Q;
4940 else if (s == SV_STCONN)
4941 t->flags |= SN_FINST_C;
4942 else
4943 t->flags |= SN_FINST_D;
4944 }
willy tarreau0f7af912005-12-17 12:21:26 +01004945 return 1;
4946 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004947 /* last read, or end of server write */
4948 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004949 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004950 tv_eternity(&t->crexpire);
4951 shutdown(t->cli_fd, SHUT_RD);
4952 t->cli_state = CL_STSHUTR;
4953 return 1;
4954 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004955 /* last server read and buffer empty */
4956 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004957 FD_CLR(t->cli_fd, StaticWriteEvent);
4958 tv_eternity(&t->cwexpire);
4959 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004960 /* We must ensure that the read part is still alive when switching
4961 * to shutw */
4962 FD_SET(t->cli_fd, StaticReadEvent);
4963 if (t->proxy->clitimeout)
4964 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004965 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004966 //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 +01004967 return 1;
4968 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004969 /* read timeout */
4970 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4971 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004972 tv_eternity(&t->crexpire);
4973 shutdown(t->cli_fd, SHUT_RD);
4974 t->cli_state = CL_STSHUTR;
4975 if (!(t->flags & SN_ERR_MASK))
4976 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004977 if (!(t->flags & SN_FINST_MASK)) {
4978 if (t->pend_pos)
4979 t->flags |= SN_FINST_Q;
4980 else if (s == SV_STCONN)
4981 t->flags |= SN_FINST_C;
4982 else
4983 t->flags |= SN_FINST_D;
4984 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004985 return 1;
4986 }
4987 /* write timeout */
4988 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4989 FD_CLR(t->cli_fd, StaticWriteEvent);
4990 tv_eternity(&t->cwexpire);
4991 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004992 /* We must ensure that the read part is still alive when switching
4993 * to shutw */
4994 FD_SET(t->cli_fd, StaticReadEvent);
4995 if (t->proxy->clitimeout)
4996 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4997
willy tarreau036e1ce2005-12-17 13:46:33 +01004998 t->cli_state = CL_STSHUTW;
4999 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01005000 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005001 if (!(t->flags & SN_FINST_MASK)) {
5002 if (t->pend_pos)
5003 t->flags |= SN_FINST_Q;
5004 else if (s == SV_STCONN)
5005 t->flags |= SN_FINST_C;
5006 else
5007 t->flags |= SN_FINST_D;
5008 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005009 return 1;
5010 }
willy tarreau0f7af912005-12-17 12:21:26 +01005011
willy tarreauc58fc692005-12-17 14:13:08 +01005012 if (req->l >= req->rlim - req->data) {
5013 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01005014 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01005015 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01005016 FD_CLR(t->cli_fd, StaticReadEvent);
5017 tv_eternity(&t->crexpire);
5018 }
5019 }
5020 else {
willy tarreauef900ab2005-12-17 12:52:52 +01005021 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01005022 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
5023 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01005024 if (!t->proxy->clitimeout ||
5025 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
5026 /* If the client has no timeout, or if the server not ready yet, and we
5027 * know for sure that it can expire, then it's cleaner to disable the
5028 * timeout on the client side so that too low values cannot make the
5029 * sessions abort too early.
5030 */
willy tarreau0f7af912005-12-17 12:21:26 +01005031 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01005032 else
5033 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005034 }
5035 }
5036
5037 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01005038 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005039 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5040 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
5041 tv_eternity(&t->cwexpire);
5042 }
5043 }
5044 else { /* buffer not empty */
5045 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5046 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005047 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005048 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005049 /* FIXME: to prevent the client from expiring read timeouts during writes,
5050 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005051 t->crexpire = t->cwexpire;
5052 }
willy tarreau0f7af912005-12-17 12:21:26 +01005053 else
5054 tv_eternity(&t->cwexpire);
5055 }
5056 }
5057 return 0; /* other cases change nothing */
5058 }
5059 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005060 if (t->res_cw == RES_ERROR) {
5061 tv_eternity(&t->cwexpire);
5062 fd_delete(t->cli_fd);
5063 t->cli_state = CL_STCLOSE;
5064 if (!(t->flags & SN_ERR_MASK))
5065 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02005066 if (!(t->flags & SN_FINST_MASK)) {
5067 if (t->pend_pos)
5068 t->flags |= SN_FINST_Q;
5069 else if (s == SV_STCONN)
5070 t->flags |= SN_FINST_C;
5071 else
5072 t->flags |= SN_FINST_D;
5073 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005074 return 1;
5075 }
willy tarreaue0331262006-05-15 03:02:46 +02005076 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
5077 && !(t->flags & SN_SELF_GEN)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005078 tv_eternity(&t->cwexpire);
5079 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005080 t->cli_state = CL_STCLOSE;
5081 return 1;
5082 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005083 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
5084 tv_eternity(&t->cwexpire);
5085 fd_delete(t->cli_fd);
5086 t->cli_state = CL_STCLOSE;
5087 if (!(t->flags & SN_ERR_MASK))
5088 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005089 if (!(t->flags & SN_FINST_MASK)) {
5090 if (t->pend_pos)
5091 t->flags |= SN_FINST_Q;
5092 else if (s == SV_STCONN)
5093 t->flags |= SN_FINST_C;
5094 else
5095 t->flags |= SN_FINST_D;
5096 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005097 return 1;
5098 }
willy tarreaue0331262006-05-15 03:02:46 +02005099
5100 if (t->flags & SN_SELF_GEN) {
5101 produce_content(t);
5102 if (rep->l == 0) {
5103 tv_eternity(&t->cwexpire);
5104 fd_delete(t->cli_fd);
5105 t->cli_state = CL_STCLOSE;
5106 return 1;
5107 }
5108 }
5109
5110 if ((rep->l == 0)
5111 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005112 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5113 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
5114 tv_eternity(&t->cwexpire);
5115 }
5116 }
5117 else { /* buffer not empty */
5118 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5119 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005120 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005121 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005122 /* FIXME: to prevent the client from expiring read timeouts during writes,
5123 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005124 t->crexpire = t->cwexpire;
5125 }
willy tarreau0f7af912005-12-17 12:21:26 +01005126 else
5127 tv_eternity(&t->cwexpire);
5128 }
5129 }
5130 return 0;
5131 }
5132 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005133 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005134 tv_eternity(&t->crexpire);
5135 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005136 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005137 if (!(t->flags & SN_ERR_MASK))
5138 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02005139 if (!(t->flags & SN_FINST_MASK)) {
5140 if (t->pend_pos)
5141 t->flags |= SN_FINST_Q;
5142 else if (s == SV_STCONN)
5143 t->flags |= SN_FINST_C;
5144 else
5145 t->flags |= SN_FINST_D;
5146 }
willy tarreau0f7af912005-12-17 12:21:26 +01005147 return 1;
5148 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005149 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
5150 tv_eternity(&t->crexpire);
5151 fd_delete(t->cli_fd);
5152 t->cli_state = CL_STCLOSE;
5153 return 1;
5154 }
5155 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
5156 tv_eternity(&t->crexpire);
5157 fd_delete(t->cli_fd);
5158 t->cli_state = CL_STCLOSE;
5159 if (!(t->flags & SN_ERR_MASK))
5160 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005161 if (!(t->flags & SN_FINST_MASK)) {
5162 if (t->pend_pos)
5163 t->flags |= SN_FINST_Q;
5164 else if (s == SV_STCONN)
5165 t->flags |= SN_FINST_C;
5166 else
5167 t->flags |= SN_FINST_D;
5168 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005169 return 1;
5170 }
willy tarreauef900ab2005-12-17 12:52:52 +01005171 else if (req->l >= req->rlim - req->data) {
5172 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01005173
5174 /* FIXME-20050705: is it possible for a client to maintain a session
5175 * after the timeout by sending more data after it receives a close ?
5176 */
5177
willy tarreau0f7af912005-12-17 12:21:26 +01005178 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01005179 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01005180 FD_CLR(t->cli_fd, StaticReadEvent);
5181 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01005182 //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 +01005183 }
5184 }
5185 else {
willy tarreauef900ab2005-12-17 12:52:52 +01005186 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01005187 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
5188 FD_SET(t->cli_fd, StaticReadEvent);
5189 if (t->proxy->clitimeout)
5190 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
5191 else
5192 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01005193 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01005194 }
5195 }
5196 return 0;
5197 }
5198 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005199 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005200 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005201 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 +01005202 write(1, trash, len);
5203 }
5204 return 0;
5205 }
5206 return 0;
5207}
5208
willy tarreaudfece232006-05-02 00:19:57 +02005209/* This function turns the server state into the SV_STCLOSE, and sets
5210 * indicators accordingly. Note that if <status> is 0, no message is
5211 * returned.
5212 */
5213void srv_close_with_err(struct session *t, int err, int finst, int status, int msglen, char *msg) {
5214 t->srv_state = SV_STCLOSE;
5215 if (status > 0) {
5216 t->logs.status = status;
5217 if (t->proxy->mode == PR_MODE_HTTP)
5218 client_return(t, msglen, msg);
5219 }
5220 if (!(t->flags & SN_ERR_MASK))
5221 t->flags |= err;
5222 if (!(t->flags & SN_FINST_MASK))
5223 t->flags |= finst;
5224}
5225
5226/*
5227 * This function checks the retry count during the connect() job.
5228 * It updates the session's srv_state and retries, so that the caller knows
5229 * what it has to do. It uses the last connection error to set the log when
5230 * it expires. It returns 1 when it has expired, and 0 otherwise.
5231 */
5232int srv_count_retry_down(struct session *t, int conn_err) {
5233 /* we are in front of a retryable error */
5234 t->conn_retries--;
5235 if (t->conn_retries < 0) {
5236 /* if not retryable anymore, let's abort */
5237 tv_eternity(&t->cnexpire);
5238 srv_close_with_err(t, conn_err, SN_FINST_C,
5239 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaue3b30652006-05-21 16:23:22 +02005240 if (t->srv)
5241 t->srv->failed_conns++;
5242 t->proxy->failed_conns++;
5243
willy tarreaudfece232006-05-02 00:19:57 +02005244 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005245 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005246 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005247 if (may_dequeue_tasks(t->srv, t->proxy))
5248 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005249 return 1;
5250 }
5251 return 0;
5252}
willy tarreau0f7af912005-12-17 12:21:26 +01005253
5254/*
willy tarreaudfece232006-05-02 00:19:57 +02005255 * This function performs the retryable part of the connect() job.
5256 * It updates the session's srv_state and retries, so that the caller knows
5257 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
5258 * it needs to redispatch.
5259 */
5260int srv_retryable_connect(struct session *t) {
5261 int conn_err;
5262
5263 /* This loop ensures that we stop before the last retry in case of a
5264 * redispatchable server.
5265 */
5266 do {
5267 /* initiate a connection to the server */
5268 conn_err = connect_server(t);
5269 switch (conn_err) {
5270
5271 case SN_ERR_NONE:
5272 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
5273 t->srv_state = SV_STCONN;
5274 return 1;
5275
5276 case SN_ERR_INTERNAL:
5277 tv_eternity(&t->cnexpire);
5278 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
5279 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreaue3b30652006-05-21 16:23:22 +02005280 if (t->srv)
5281 t->srv->failed_conns++;
5282 t->proxy->failed_conns++;
willy tarreaudfece232006-05-02 00:19:57 +02005283 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02005284 if (may_dequeue_tasks(t->srv, t->proxy))
5285 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005286 return 1;
5287 }
5288 /* ensure that we have enough retries left */
willy tarreau59a6cc22006-05-12 01:29:08 +02005289 if (srv_count_retry_down(t, conn_err)) {
5290 /* let's try to offer this slot to anybody */
5291 if (may_dequeue_tasks(t->srv, t->proxy))
5292 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005293 return 1;
willy tarreau59a6cc22006-05-12 01:29:08 +02005294 }
willy tarreaudfece232006-05-02 00:19:57 +02005295 } while (t->srv == NULL || t->conn_retries > 0 || !(t->proxy->options & PR_O_REDISP));
5296
5297 /* We're on our last chance, and the REDISP option was specified.
5298 * We will ignore cookie and force to balance or use the dispatcher.
5299 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005300 /* let's try to offer this slot to anybody */
5301 if (may_dequeue_tasks(t->srv, t->proxy))
5302 task_wakeup(&rq, t->srv->queue_mgt);
5303
willy tarreaue3b30652006-05-21 16:23:22 +02005304 if (t->srv)
5305 t->srv->failed_conns++;
5306 t->proxy->failed_conns++;
5307
willy tarreaudfece232006-05-02 00:19:57 +02005308 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
5309 t->srv = NULL; /* it's left to the dispatcher to choose a server */
5310 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
5311 t->flags &= ~SN_CK_MASK;
5312 t->flags |= SN_CK_DOWN;
5313 }
5314 return 0;
5315}
5316
5317/* This function performs the "redispatch" part of a connection attempt. It
5318 * will assign a server if required, queue the connection if required, and
5319 * handle errors that might arise at this level. It can change the server
5320 * state. It will return 1 if it encounters an error, switches the server
5321 * state, or has to queue a connection. Otherwise, it will return 0 indicating
5322 * that the connection is ready to use.
5323 */
5324
5325int srv_redispatch_connect(struct session *t) {
5326 int conn_err;
5327
5328 /* We know that we don't have any connection pending, so we will
5329 * try to get a new one, and wait in this state if it's queued
5330 */
5331 conn_err = assign_server_and_queue(t);
5332 switch (conn_err) {
5333 case SRV_STATUS_OK:
5334 break;
5335
5336 case SRV_STATUS_NOSRV:
willy tarreau59a6cc22006-05-12 01:29:08 +02005337 /* note: it is guaranteed that t->srv == NULL here */
willy tarreaudfece232006-05-02 00:19:57 +02005338 tv_eternity(&t->cnexpire);
5339 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
5340 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaue3b30652006-05-21 16:23:22 +02005341 if (t->srv)
5342 t->srv->failed_conns++;
5343 t->proxy->failed_conns++;
5344
willy tarreaudfece232006-05-02 00:19:57 +02005345 return 1;
5346
5347 case SRV_STATUS_QUEUED:
willy tarreau45526ed2006-05-03 20:11:50 +02005348 /* FIXME-20060503 : we should use the queue timeout instead */
5349 if (t->proxy->contimeout)
5350 tv_delayfrom(&t->cnexpire, &now, t->proxy->contimeout);
5351 else
5352 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02005353 t->srv_state = SV_STIDLE;
5354 /* do nothing else and do not wake any other session up */
5355 return 1;
5356
5357 case SRV_STATUS_FULL:
5358 case SRV_STATUS_INTERNAL:
5359 default:
5360 tv_eternity(&t->cnexpire);
5361 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
5362 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreaue3b30652006-05-21 16:23:22 +02005363 if (t->srv)
5364 t->srv->failed_conns++;
5365 t->proxy->failed_conns++;
5366
willy tarreaudfece232006-05-02 00:19:57 +02005367 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02005368 if (may_dequeue_tasks(t->srv, t->proxy))
5369 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005370 return 1;
5371 }
5372 /* if we get here, it's because we got SRV_STATUS_OK, which also
5373 * means that the connection has not been queued.
5374 */
5375 return 0;
5376}
5377
5378
5379/*
willy tarreau0f7af912005-12-17 12:21:26 +01005380 * manages the server FSM and its socket. It returns 1 if a state has changed
5381 * (and a resync may be needed), 0 else.
5382 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005383int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01005384 int s = t->srv_state;
5385 int c = t->cli_state;
5386 struct buffer *req = t->req;
5387 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01005388 appsess *asession_temp = NULL;
5389 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01005390 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01005391
willy tarreau750a4722005-12-17 13:21:24 +01005392#ifdef DEBUG_FULL
5393 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
5394#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01005395 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
5396 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
5397 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
5398 //);
willy tarreau0f7af912005-12-17 12:21:26 +01005399 if (s == SV_STIDLE) {
5400 if (c == CL_STHEADERS)
5401 return 0; /* stay in idle, waiting for data to reach the client side */
5402 else if (c == CL_STCLOSE ||
5403 c == CL_STSHUTW ||
5404 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
5405 tv_eternity(&t->cnexpire);
willy tarreau424e04a2006-05-13 16:08:47 +02005406 if (t->pend_pos)
5407 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreau51e91292006-05-14 23:29:47 +02005408 /* note that this must not return any error because it would be able to
5409 * overwrite the client_retnclose() output.
5410 */
willy tarreau078c79a2006-05-13 12:23:58 +02005411 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 +02005412
willy tarreau0f7af912005-12-17 12:21:26 +01005413 return 1;
5414 }
willy tarreaudfece232006-05-02 00:19:57 +02005415 else {
5416 /* Right now, we will need to create a connection to the server.
5417 * We might already have tried, and got a connection pending, in
5418 * which case we will not do anything till it's pending. It's up
5419 * to any other session to release it and wake us up again.
5420 */
willy tarreau45526ed2006-05-03 20:11:50 +02005421 if (t->pend_pos) {
5422 if (tv_cmp2_ms(&t->cnexpire, &now) > 0)
5423 return 0;
5424 else {
5425 /* we've been waiting too long here */
5426 tv_eternity(&t->cnexpire);
willy tarreau078c79a2006-05-13 12:23:58 +02005427 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
5428 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
willy tarreau45526ed2006-05-03 20:11:50 +02005429 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaue3b30652006-05-21 16:23:22 +02005430 if (t->srv)
5431 t->srv->failed_conns++;
5432 t->proxy->failed_conns++;
willy tarreau45526ed2006-05-03 20:11:50 +02005433 return 1;
5434 }
5435 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005436
willy tarreaudfece232006-05-02 00:19:57 +02005437 do {
5438 /* first, get a connection */
5439 if (srv_redispatch_connect(t))
5440 return t->srv_state != SV_STIDLE;
5441
5442 /* try to (re-)connect to the server, and fail if we expire the
5443 * number of retries.
5444 */
willy tarreauf32f5242006-05-02 22:54:52 +02005445 if (srv_retryable_connect(t)) {
5446 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02005447 return t->srv_state != SV_STIDLE;
willy tarreauf32f5242006-05-02 22:54:52 +02005448 }
willy tarreaudfece232006-05-02 00:19:57 +02005449
5450 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01005451 }
5452 }
5453 else if (s == SV_STCONN) { /* connection in progress */
5454 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01005455 //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 +01005456 return 0; /* nothing changed */
5457 }
5458 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
willy tarreaudfece232006-05-02 00:19:57 +02005459 /* timeout, asynchronous connect error or first write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005460 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
willy tarreaudfece232006-05-02 00:19:57 +02005461
willy tarreau0f7af912005-12-17 12:21:26 +01005462 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005463 if (t->srv)
5464 t->srv->cur_sess--;
willy tarreaudfece232006-05-02 00:19:57 +02005465
5466 if (t->res_sw == RES_SILENT)
willy tarreaub1285d52005-12-18 01:20:14 +01005467 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
5468 else
willy tarreaudfece232006-05-02 00:19:57 +02005469 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
willy tarreaub1285d52005-12-18 01:20:14 +01005470
willy tarreaudfece232006-05-02 00:19:57 +02005471 /* ensure that we have enough retries left */
5472 if (srv_count_retry_down(t, conn_err))
5473 return 1;
5474
5475 do {
5476 /* Now we will try to either reconnect to the same server or
5477 * connect to another server. If the connection gets queued
5478 * because all servers are saturated, then we will go back to
5479 * the SV_STIDLE state.
5480 */
willy tarreauf32f5242006-05-02 22:54:52 +02005481 if (srv_retryable_connect(t)) {
5482 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02005483 return t->srv_state != SV_STCONN;
willy tarreauf32f5242006-05-02 22:54:52 +02005484 }
willy tarreaudfece232006-05-02 00:19:57 +02005485
5486 /* we need to redispatch the connection to another server */
5487 if (srv_redispatch_connect(t))
5488 return t->srv_state != SV_STCONN;
5489 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01005490 }
5491 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01005492 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005493
willy tarreau0f7af912005-12-17 12:21:26 +01005494 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005495 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01005496 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005497 tv_eternity(&t->swexpire);
5498 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01005499 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005500 if (t->proxy->srvtimeout) {
5501 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005502 /* FIXME: to prevent the server from expiring read timeouts during writes,
5503 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005504 t->srexpire = t->swexpire;
5505 }
5506 else
5507 tv_eternity(&t->swexpire);
5508 }
willy tarreau0f7af912005-12-17 12:21:26 +01005509
5510 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
5511 FD_SET(t->srv_fd, StaticReadEvent);
5512 if (t->proxy->srvtimeout)
5513 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5514 else
5515 tv_eternity(&t->srexpire);
5516
5517 t->srv_state = SV_STDATA;
willy tarreau2d505e52006-05-21 08:32:50 +02005518 if (t->srv)
5519 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01005520 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01005521
5522 /* if the user wants to log as soon as possible, without counting
5523 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005524 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005525 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
5526 sess_log(t);
5527 }
willy tarreau0f7af912005-12-17 12:21:26 +01005528 }
willy tarreauef900ab2005-12-17 12:52:52 +01005529 else {
willy tarreau0f7af912005-12-17 12:21:26 +01005530 t->srv_state = SV_STHEADERS;
willy tarreau2d505e52006-05-21 08:32:50 +02005531 if (t->srv)
5532 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01005533 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
5534 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005535 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005536 return 1;
5537 }
5538 }
5539 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005540 /* now parse the partial (or complete) headers */
5541 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
5542 char *ptr;
5543 int delete_header;
5544
5545 ptr = rep->lr;
5546
5547 /* look for the end of the current header */
5548 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
5549 ptr++;
5550
5551 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005552 int line, len;
5553
5554 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01005555
5556 /* first, we'll block if security checks have caught nasty things */
5557 if (t->flags & SN_CACHEABLE) {
5558 if ((t->flags & SN_CACHE_COOK) &&
5559 (t->flags & SN_SCK_ANY) &&
5560 (t->proxy->options & PR_O_CHK_CACHE)) {
5561
5562 /* we're in presence of a cacheable response containing
5563 * a set-cookie header. We'll block it as requested by
5564 * the 'checkcache' option, and send an alert.
5565 */
5566 tv_eternity(&t->srexpire);
5567 tv_eternity(&t->swexpire);
5568 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02005569 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02005570 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02005571 t->srv->failed_secu++;
5572 }
5573 t->proxy->failed_secu++;
willy tarreau97f58572005-12-18 00:53:44 +01005574 t->srv_state = SV_STCLOSE;
5575 t->logs.status = 502;
5576 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
5577 if (!(t->flags & SN_ERR_MASK))
5578 t->flags |= SN_ERR_PRXCOND;
5579 if (!(t->flags & SN_FINST_MASK))
5580 t->flags |= SN_FINST_H;
5581
5582 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
5583 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
5584
willy tarreaudfece232006-05-02 00:19:57 +02005585 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005586 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005587 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005588 if (may_dequeue_tasks(t->srv, t->proxy))
5589 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005590
willy tarreau97f58572005-12-18 00:53:44 +01005591 return 1;
5592 }
5593 }
5594
willy tarreau982249e2005-12-18 00:57:06 +01005595 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
5596 if (t->flags & SN_SVDENY) {
5597 tv_eternity(&t->srexpire);
5598 tv_eternity(&t->swexpire);
5599 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02005600 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02005601 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02005602 t->srv->failed_secu++;
5603 }
5604 t->proxy->failed_secu++;
willy tarreau982249e2005-12-18 00:57:06 +01005605 t->srv_state = SV_STCLOSE;
5606 t->logs.status = 502;
5607 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
5608 if (!(t->flags & SN_ERR_MASK))
5609 t->flags |= SN_ERR_PRXCOND;
5610 if (!(t->flags & SN_FINST_MASK))
5611 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005612 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005613 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005614 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005615 if (may_dequeue_tasks(t->srv, t->proxy))
5616 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005617
willy tarreau982249e2005-12-18 00:57:06 +01005618 return 1;
5619 }
5620
willy tarreau5cbea6f2005-12-17 12:48:26 +01005621 /* we'll have something else to do here : add new headers ... */
5622
willy tarreaucd878942005-12-17 13:27:43 +01005623 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
5624 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005625 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01005626 * insert a set-cookie here, except if we want to insert only on POST
willy tarreau4f7a1012006-05-09 23:32:26 +02005627 * requests and this one isn't. Note that servers which don't have cookies
5628 * (eg: some backup servers) will return a full cookie removal request.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005629 */
willy tarreau750a4722005-12-17 13:21:24 +01005630 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01005631 t->proxy->cookie_name,
willy tarreau4f7a1012006-05-09 23:32:26 +02005632 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
willy tarreau750a4722005-12-17 13:21:24 +01005633
willy tarreau036e1ce2005-12-17 13:46:33 +01005634 t->flags |= SN_SCK_INSERTED;
5635
willy tarreau750a4722005-12-17 13:21:24 +01005636 /* Here, we will tell an eventual cache on the client side that we don't
5637 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
5638 * Some caches understand the correct form: 'no-cache="set-cookie"', but
5639 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
5640 */
willy tarreau240afa62005-12-17 13:14:35 +01005641 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01005642 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
5643 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01005644
5645 if (rep->data + rep->l < rep->h)
5646 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
5647 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01005648 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005649 }
5650
5651 /* headers to be added */
5652 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01005653 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
5654 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005655 }
5656
willy tarreau25c4ea52005-12-18 00:49:49 +01005657 /* add a "connection: close" line if needed */
5658 if (t->proxy->options & PR_O_HTTP_CLOSE)
5659 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
5660
willy tarreau5cbea6f2005-12-17 12:48:26 +01005661 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01005662 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01005663 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01005664
Willy TARREAU767ba712006-03-01 22:40:50 +01005665 /* client connection already closed or option 'httpclose' required :
5666 * we close the server's outgoing connection right now.
5667 */
5668 if ((req->l == 0) &&
5669 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
5670 FD_CLR(t->srv_fd, StaticWriteEvent);
5671 tv_eternity(&t->swexpire);
5672
5673 /* We must ensure that the read part is still alive when switching
5674 * to shutw */
5675 FD_SET(t->srv_fd, StaticReadEvent);
5676 if (t->proxy->srvtimeout)
5677 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5678
5679 shutdown(t->srv_fd, SHUT_WR);
5680 t->srv_state = SV_STSHUTW;
5681 }
5682
willy tarreau25c4ea52005-12-18 00:49:49 +01005683 /* if the user wants to log as soon as possible, without counting
5684 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005685 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005686 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
5687 t->logs.bytes = rep->h - rep->data;
5688 sess_log(t);
5689 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005690 break;
5691 }
5692
5693 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
5694 if (ptr > rep->r - 2) {
5695 /* this is a partial header, let's wait for more to come */
5696 rep->lr = ptr;
5697 break;
5698 }
5699
5700 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
5701 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
5702
5703 /* now we know that *ptr is either \r or \n,
5704 * and that there are at least 1 char after it.
5705 */
5706 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
5707 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
5708 else
5709 rep->lr = ptr + 2; /* \r\n or \n\r */
5710
5711 /*
5712 * now we know that we have a full header ; we can do whatever
5713 * we want with these pointers :
5714 * rep->h = beginning of header
5715 * ptr = end of header (first \r or \n)
5716 * rep->lr = beginning of next line (next rep->h)
5717 * rep->r = end of data (not used at this stage)
5718 */
5719
willy tarreaua1598082005-12-17 13:08:06 +01005720
willy tarreau982249e2005-12-18 00:57:06 +01005721 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01005722 t->logs.logwait &= ~LW_RESP;
5723 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01005724 switch (t->logs.status) {
5725 case 200:
5726 case 203:
5727 case 206:
5728 case 300:
5729 case 301:
5730 case 410:
5731 /* RFC2616 @13.4:
5732 * "A response received with a status code of
5733 * 200, 203, 206, 300, 301 or 410 MAY be stored
5734 * by a cache (...) unless a cache-control
5735 * directive prohibits caching."
5736 *
5737 * RFC2616 @9.5: POST method :
5738 * "Responses to this method are not cacheable,
5739 * unless the response includes appropriate
5740 * Cache-Control or Expires header fields."
5741 */
willy tarreau7476ec92006-05-21 16:24:15 +02005742 if (!(t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
willy tarreau982249e2005-12-18 00:57:06 +01005743 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
5744 break;
5745 default:
5746 break;
5747 }
willy tarreau4302f492005-12-18 01:00:37 +01005748 }
5749 else if (t->logs.logwait & LW_RSPHDR) {
5750 struct cap_hdr *h;
5751 int len;
5752 for (h = t->proxy->rsp_cap; h; h = h->next) {
5753 if ((h->namelen + 2 <= ptr - rep->h) &&
5754 (rep->h[h->namelen] == ':') &&
5755 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
5756
5757 if (t->rsp_cap[h->index] == NULL)
5758 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
5759
5760 len = ptr - (rep->h + h->namelen + 2);
5761 if (len > h->len)
5762 len = h->len;
5763
5764 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
5765 t->rsp_cap[h->index][len]=0;
5766 }
5767 }
5768
willy tarreaua1598082005-12-17 13:08:06 +01005769 }
5770
willy tarreau5cbea6f2005-12-17 12:48:26 +01005771 delete_header = 0;
5772
willy tarreau982249e2005-12-18 00:57:06 +01005773 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005774 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01005775 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 +01005776 max = ptr - rep->h;
5777 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01005778 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005779 trash[len++] = '\n';
5780 write(1, trash, len);
5781 }
5782
willy tarreau25c4ea52005-12-18 00:49:49 +01005783 /* remove "connection: " if needed */
5784 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
5785 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
5786 delete_header = 1;
5787 }
5788
willy tarreau5cbea6f2005-12-17 12:48:26 +01005789 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01005790 if (!delete_header && t->proxy->rsp_exp != NULL
5791 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01005792 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005793 char term;
5794
5795 term = *ptr;
5796 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01005797 exp = t->proxy->rsp_exp;
5798 do {
5799 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
5800 switch (exp->action) {
5801 case ACT_ALLOW:
5802 if (!(t->flags & SN_SVDENY))
5803 t->flags |= SN_SVALLOW;
5804 break;
5805 case ACT_REPLACE:
5806 if (!(t->flags & SN_SVDENY)) {
5807 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
5808 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
5809 }
5810 break;
5811 case ACT_REMOVE:
5812 if (!(t->flags & SN_SVDENY))
5813 delete_header = 1;
5814 break;
5815 case ACT_DENY:
5816 if (!(t->flags & SN_SVALLOW))
5817 t->flags |= SN_SVDENY;
5818 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01005819 case ACT_PASS: /* we simply don't deny this one */
5820 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005821 }
5822 break;
5823 }
willy tarreaue39cd132005-12-17 13:00:18 +01005824 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005825 *ptr = term; /* restore the string terminator */
5826 }
5827
willy tarreau97f58572005-12-18 00:53:44 +01005828 /* check for cache-control: or pragma: headers */
5829 if (!delete_header && (t->flags & SN_CACHEABLE)) {
5830 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
5831 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5832 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
5833 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01005834 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01005835 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5836 else {
5837 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01005838 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005839 t->flags &= ~SN_CACHE_COOK;
5840 }
5841 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005842 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005843 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005844 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01005845 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5846 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005847 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01005848 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01005849 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
5850 (rep->h + 25 == ptr || rep->h[25] == ',')) {
5851 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5852 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
5853 (rep->h + 21 == ptr || rep->h[21] == ',')) {
5854 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01005855 }
5856 }
5857 }
5858
willy tarreau5cbea6f2005-12-17 12:48:26 +01005859 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01005860 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01005861 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01005862 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005863 char *p1, *p2, *p3, *p4;
5864
willy tarreau97f58572005-12-18 00:53:44 +01005865 t->flags |= SN_SCK_ANY;
5866
willy tarreau5cbea6f2005-12-17 12:48:26 +01005867 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
5868
5869 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01005870 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005871 p1++;
5872
5873 if (p1 == ptr || *p1 == ';') /* end of cookie */
5874 break;
5875
5876 /* p1 is at the beginning of the cookie name */
5877 p2 = p1;
5878
5879 while (p2 < ptr && *p2 != '=' && *p2 != ';')
5880 p2++;
5881
5882 if (p2 == ptr || *p2 == ';') /* next cookie */
5883 break;
5884
5885 p3 = p2 + 1; /* skips the '=' sign */
5886 if (p3 == ptr)
5887 break;
5888
5889 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01005890 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01005891 p4++;
5892
5893 /* here, we have the cookie name between p1 and p2,
5894 * and its value between p3 and p4.
5895 * we can process it.
5896 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005897
5898 /* first, let's see if we want to capture it */
5899 if (t->proxy->capture_name != NULL &&
5900 t->logs.srv_cookie == NULL &&
5901 (p4 - p1 >= t->proxy->capture_namelen) &&
5902 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
5903 int log_len = p4 - p1;
5904
5905 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
5906 Alert("HTTP logging : out of memory.\n");
5907 }
5908
5909 if (log_len > t->proxy->capture_len)
5910 log_len = t->proxy->capture_len;
5911 memcpy(t->logs.srv_cookie, p1, log_len);
5912 t->logs.srv_cookie[log_len] = 0;
5913 }
5914
5915 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
5916 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005917 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01005918 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005919
5920 /* If the cookie is in insert mode on a known server, we'll delete
5921 * this occurrence because we'll insert another one later.
5922 * We'll delete it too if the "indirect" option is set and we're in
5923 * a direct access. */
5924 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01005925 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005926 /* this header must be deleted */
5927 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01005928 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005929 }
5930 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
5931 /* replace bytes p3->p4 with the cookie name associated
5932 * with this server since we know it.
5933 */
5934 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01005935 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005936 }
willy tarreau0174f312005-12-18 01:02:42 +01005937 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
5938 /* insert the cookie name associated with this server
5939 * before existing cookie, and insert a delimitor between them..
5940 */
5941 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
5942 p3[t->srv->cklen] = COOKIE_DELIM;
5943 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
5944 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005945 break;
5946 }
willy tarreau12350152005-12-18 01:03:27 +01005947
5948 /* first, let's see if the cookie is our appcookie*/
5949 if ((t->proxy->appsession_name != NULL) &&
5950 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
5951
5952 /* Cool... it's the right one */
5953
willy tarreaub952e1d2005-12-18 01:31:20 +01005954 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01005955 asession_temp = &local_asession;
5956
willy tarreaub952e1d2005-12-18 01:31:20 +01005957 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005958 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5959 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5960 }
5961 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
5962 asession_temp->sessid[t->proxy->appsession_len] = 0;
5963 asession_temp->serverid = NULL;
5964
5965 /* only do insert, if lookup fails */
5966 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
5967 if ((asession_temp = pool_alloc(appsess)) == NULL) {
5968 Alert("Not enought Memory process_srv():asession:calloc().\n");
5969 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
5970 return 0;
5971 }
5972 asession_temp->sessid = local_asession.sessid;
5973 asession_temp->serverid = local_asession.serverid;
5974 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01005975 }/* end if (chtbl_lookup()) */
5976 else {
willy tarreau12350152005-12-18 01:03:27 +01005977 /* free wasted memory */
5978 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01005979 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01005980
willy tarreaub952e1d2005-12-18 01:31:20 +01005981 if (asession_temp->serverid == NULL) {
5982 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005983 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5984 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5985 }
5986 asession_temp->serverid[0] = '\0';
5987 }
5988
willy tarreaub952e1d2005-12-18 01:31:20 +01005989 if (asession_temp->serverid[0] == '\0')
5990 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01005991
5992 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
5993
5994#if defined(DEBUG_HASH)
5995 print_table(&(t->proxy->htbl_proxy));
5996#endif
5997 break;
5998 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005999 else {
6000 // fprintf(stderr,"Ignoring unknown cookie : ");
6001 // write(2, p1, p2-p1);
6002 // fprintf(stderr," = ");
6003 // write(2, p3, p4-p3);
6004 // fprintf(stderr,"\n");
6005 }
6006 break; /* we don't want to loop again since there cannot be another cookie on the same line */
6007 } /* we're now at the end of the cookie value */
6008 } /* end of cookie processing */
6009
willy tarreau97f58572005-12-18 00:53:44 +01006010 /* check for any set-cookie in case we check for cacheability */
6011 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
6012 (t->proxy->options & PR_O_CHK_CACHE) &&
6013 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
6014 t->flags |= SN_SCK_ANY;
6015 }
6016
willy tarreau5cbea6f2005-12-17 12:48:26 +01006017 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01006018 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006019 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01006020
willy tarreau5cbea6f2005-12-17 12:48:26 +01006021 rep->h = rep->lr;
6022 } /* while (rep->lr < rep->r) */
6023
6024 /* end of header processing (even if incomplete) */
6025
willy tarreauef900ab2005-12-17 12:52:52 +01006026 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6027 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
6028 * full. We cannot loop here since event_srv_read will disable it only if
6029 * rep->l == rlim-data
6030 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006031 FD_SET(t->srv_fd, StaticReadEvent);
6032 if (t->proxy->srvtimeout)
6033 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6034 else
6035 tv_eternity(&t->srexpire);
6036 }
willy tarreau0f7af912005-12-17 12:21:26 +01006037
willy tarreau8337c6b2005-12-17 13:41:01 +01006038 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01006039 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01006040 tv_eternity(&t->srexpire);
6041 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006042 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006043 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006044 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006045 t->srv->failed_resp++;
6046 }
6047 t->proxy->failed_resp++;
6048
willy tarreau0f7af912005-12-17 12:21:26 +01006049 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01006050 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01006051 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01006052 if (!(t->flags & SN_ERR_MASK))
6053 t->flags |= SN_ERR_SRVCL;
6054 if (!(t->flags & SN_FINST_MASK))
6055 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02006056 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006057 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006058 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006059 if (may_dequeue_tasks(t->srv, t->proxy))
6060 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006061
willy tarreau0f7af912005-12-17 12:21:26 +01006062 return 1;
6063 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006064 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01006065 * since we are in header mode, if there's no space left for headers, we
6066 * won't be able to free more later, so the session will never terminate.
6067 */
willy tarreau8337c6b2005-12-17 13:41:01 +01006068 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 +01006069 FD_CLR(t->srv_fd, StaticReadEvent);
6070 tv_eternity(&t->srexpire);
6071 shutdown(t->srv_fd, SHUT_RD);
6072 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01006073 //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 +01006074 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006075 }
6076 /* read timeout : return a 504 to the client.
6077 */
6078 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6079 tv_eternity(&t->srexpire);
6080 tv_eternity(&t->swexpire);
6081 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006082 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006083 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006084 t->srv->failed_resp++;
6085 }
6086 t->proxy->failed_resp++;
willy tarreau8337c6b2005-12-17 13:41:01 +01006087 t->srv_state = SV_STCLOSE;
6088 t->logs.status = 504;
6089 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01006090 if (!(t->flags & SN_ERR_MASK))
6091 t->flags |= SN_ERR_SRVTO;
6092 if (!(t->flags & SN_FINST_MASK))
6093 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02006094 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006095 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006096 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006097 if (may_dequeue_tasks(t->srv, t->proxy))
6098 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006099
willy tarreau8337c6b2005-12-17 13:41:01 +01006100 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006101 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006102 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01006103 /* FIXME!!! here, we don't want to switch to SHUTW if the
6104 * client shuts read too early, because we may still have
6105 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01006106 * The side-effect is that if the client completely closes its
6107 * connection during SV_STHEADER, the connection to the server
6108 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01006109 */
willy tarreau036e1ce2005-12-17 13:46:33 +01006110 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01006111 FD_CLR(t->srv_fd, StaticWriteEvent);
6112 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01006113
6114 /* We must ensure that the read part is still alive when switching
6115 * to shutw */
6116 FD_SET(t->srv_fd, StaticReadEvent);
6117 if (t->proxy->srvtimeout)
6118 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6119
willy tarreau0f7af912005-12-17 12:21:26 +01006120 shutdown(t->srv_fd, SHUT_WR);
6121 t->srv_state = SV_STSHUTW;
6122 return 1;
6123 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006124 /* write timeout */
6125 /* FIXME!!! here, we don't want to switch to SHUTW if the
6126 * client shuts read too early, because we may still have
6127 * some work to do on the headers.
6128 */
6129 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
6130 FD_CLR(t->srv_fd, StaticWriteEvent);
6131 tv_eternity(&t->swexpire);
6132 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006133 /* We must ensure that the read part is still alive when switching
6134 * to shutw */
6135 FD_SET(t->srv_fd, StaticReadEvent);
6136 if (t->proxy->srvtimeout)
6137 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6138
6139 /* We must ensure that the read part is still alive when switching
6140 * to shutw */
6141 FD_SET(t->srv_fd, StaticReadEvent);
6142 if (t->proxy->srvtimeout)
6143 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6144
willy tarreau036e1ce2005-12-17 13:46:33 +01006145 t->srv_state = SV_STSHUTW;
6146 if (!(t->flags & SN_ERR_MASK))
6147 t->flags |= SN_ERR_SRVTO;
6148 if (!(t->flags & SN_FINST_MASK))
6149 t->flags |= SN_FINST_H;
6150 return 1;
6151 }
willy tarreau0f7af912005-12-17 12:21:26 +01006152
6153 if (req->l == 0) {
6154 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6155 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6156 tv_eternity(&t->swexpire);
6157 }
6158 }
6159 else { /* client buffer not empty */
6160 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6161 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006162 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006163 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006164 /* FIXME: to prevent the server from expiring read timeouts during writes,
6165 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006166 t->srexpire = t->swexpire;
6167 }
willy tarreau0f7af912005-12-17 12:21:26 +01006168 else
6169 tv_eternity(&t->swexpire);
6170 }
6171 }
6172
willy tarreau5cbea6f2005-12-17 12:48:26 +01006173 /* be nice with the client side which would like to send a complete header
6174 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
6175 * would read all remaining data at once ! The client should not write past rep->lr
6176 * when the server is in header state.
6177 */
6178 //return header_processed;
6179 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01006180 }
6181 else if (s == SV_STDATA) {
6182 /* read or write error */
6183 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01006184 tv_eternity(&t->srexpire);
6185 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006186 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006187 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006188 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006189 t->srv->failed_resp++;
6190 }
6191 t->proxy->failed_resp++;
willy tarreau0f7af912005-12-17 12:21:26 +01006192 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01006193 if (!(t->flags & SN_ERR_MASK))
6194 t->flags |= SN_ERR_SRVCL;
6195 if (!(t->flags & SN_FINST_MASK))
6196 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006197 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006198 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006199 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006200 if (may_dequeue_tasks(t->srv, t->proxy))
6201 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006202
willy tarreau0f7af912005-12-17 12:21:26 +01006203 return 1;
6204 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006205 /* last read, or end of client write */
6206 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01006207 FD_CLR(t->srv_fd, StaticReadEvent);
6208 tv_eternity(&t->srexpire);
6209 shutdown(t->srv_fd, SHUT_RD);
6210 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01006211 //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 +01006212 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01006213 }
6214 /* end of client read and no more data to send */
6215 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
6216 FD_CLR(t->srv_fd, StaticWriteEvent);
6217 tv_eternity(&t->swexpire);
6218 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006219 /* We must ensure that the read part is still alive when switching
6220 * to shutw */
6221 FD_SET(t->srv_fd, StaticReadEvent);
6222 if (t->proxy->srvtimeout)
6223 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6224
willy tarreaua41a8b42005-12-17 14:02:24 +01006225 t->srv_state = SV_STSHUTW;
6226 return 1;
6227 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006228 /* read timeout */
6229 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6230 FD_CLR(t->srv_fd, StaticReadEvent);
6231 tv_eternity(&t->srexpire);
6232 shutdown(t->srv_fd, SHUT_RD);
6233 t->srv_state = SV_STSHUTR;
6234 if (!(t->flags & SN_ERR_MASK))
6235 t->flags |= SN_ERR_SRVTO;
6236 if (!(t->flags & SN_FINST_MASK))
6237 t->flags |= SN_FINST_D;
6238 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006239 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006240 /* write timeout */
6241 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01006242 FD_CLR(t->srv_fd, StaticWriteEvent);
6243 tv_eternity(&t->swexpire);
6244 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006245 /* We must ensure that the read part is still alive when switching
6246 * to shutw */
6247 FD_SET(t->srv_fd, StaticReadEvent);
6248 if (t->proxy->srvtimeout)
6249 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01006250 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01006251 if (!(t->flags & SN_ERR_MASK))
6252 t->flags |= SN_ERR_SRVTO;
6253 if (!(t->flags & SN_FINST_MASK))
6254 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01006255 return 1;
6256 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01006257
6258 /* recompute request time-outs */
6259 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01006260 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6261 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6262 tv_eternity(&t->swexpire);
6263 }
6264 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01006265 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01006266 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6267 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006268 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006269 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006270 /* FIXME: to prevent the server from expiring read timeouts during writes,
6271 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006272 t->srexpire = t->swexpire;
6273 }
willy tarreau0f7af912005-12-17 12:21:26 +01006274 else
6275 tv_eternity(&t->swexpire);
6276 }
6277 }
6278
willy tarreaub1ff9db2005-12-17 13:51:03 +01006279 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01006280 if (rep->l == BUFSIZE) { /* no room to read more data */
6281 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
6282 FD_CLR(t->srv_fd, StaticReadEvent);
6283 tv_eternity(&t->srexpire);
6284 }
6285 }
6286 else {
6287 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6288 FD_SET(t->srv_fd, StaticReadEvent);
6289 if (t->proxy->srvtimeout)
6290 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6291 else
6292 tv_eternity(&t->srexpire);
6293 }
6294 }
6295
6296 return 0; /* other cases change nothing */
6297 }
6298 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006299 if (t->res_sw == RES_ERROR) {
6300 //FD_CLR(t->srv_fd, StaticWriteEvent);
6301 tv_eternity(&t->swexpire);
6302 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006303 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006304 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006305 t->srv->failed_resp++;
6306 }
6307 t->proxy->failed_resp++;
willy tarreau036e1ce2005-12-17 13:46:33 +01006308 //close(t->srv_fd);
6309 t->srv_state = SV_STCLOSE;
6310 if (!(t->flags & SN_ERR_MASK))
6311 t->flags |= SN_ERR_SRVCL;
6312 if (!(t->flags & SN_FINST_MASK))
6313 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006314 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006315 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006316 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006317 if (may_dequeue_tasks(t->srv, t->proxy))
6318 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006319
willy tarreau036e1ce2005-12-17 13:46:33 +01006320 return 1;
6321 }
6322 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006323 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01006324 tv_eternity(&t->swexpire);
6325 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006326 if (t->srv)
6327 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006328 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01006329 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02006330 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006331 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006332 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006333 if (may_dequeue_tasks(t->srv, t->proxy))
6334 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006335
willy tarreau0f7af912005-12-17 12:21:26 +01006336 return 1;
6337 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006338 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
6339 //FD_CLR(t->srv_fd, StaticWriteEvent);
6340 tv_eternity(&t->swexpire);
6341 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006342 if (t->srv)
6343 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006344 //close(t->srv_fd);
6345 t->srv_state = SV_STCLOSE;
6346 if (!(t->flags & SN_ERR_MASK))
6347 t->flags |= SN_ERR_SRVTO;
6348 if (!(t->flags & SN_FINST_MASK))
6349 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006350 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006351 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006352 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006353 if (may_dequeue_tasks(t->srv, t->proxy))
6354 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006355
willy tarreau036e1ce2005-12-17 13:46:33 +01006356 return 1;
6357 }
willy tarreau0f7af912005-12-17 12:21:26 +01006358 else if (req->l == 0) {
6359 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6360 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6361 tv_eternity(&t->swexpire);
6362 }
6363 }
6364 else { /* buffer not empty */
6365 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6366 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006367 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006368 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006369 /* FIXME: to prevent the server from expiring read timeouts during writes,
6370 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006371 t->srexpire = t->swexpire;
6372 }
willy tarreau0f7af912005-12-17 12:21:26 +01006373 else
6374 tv_eternity(&t->swexpire);
6375 }
6376 }
6377 return 0;
6378 }
6379 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006380 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006381 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01006382 tv_eternity(&t->srexpire);
6383 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006384 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006385 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006386 t->srv->failed_resp++;
6387 }
6388 t->proxy->failed_resp++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006389 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01006390 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01006391 if (!(t->flags & SN_ERR_MASK))
6392 t->flags |= SN_ERR_SRVCL;
6393 if (!(t->flags & SN_FINST_MASK))
6394 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006395 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006396 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006397 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006398 if (may_dequeue_tasks(t->srv, t->proxy))
6399 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006400
willy tarreau0f7af912005-12-17 12:21:26 +01006401 return 1;
6402 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006403 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
6404 //FD_CLR(t->srv_fd, StaticReadEvent);
6405 tv_eternity(&t->srexpire);
6406 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006407 if (t->srv)
6408 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006409 //close(t->srv_fd);
6410 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02006411 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006412 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006413 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006414 if (may_dequeue_tasks(t->srv, t->proxy))
6415 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006416
willy tarreau036e1ce2005-12-17 13:46:33 +01006417 return 1;
6418 }
6419 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6420 //FD_CLR(t->srv_fd, StaticReadEvent);
6421 tv_eternity(&t->srexpire);
6422 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006423 if (t->srv)
6424 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006425 //close(t->srv_fd);
6426 t->srv_state = SV_STCLOSE;
6427 if (!(t->flags & SN_ERR_MASK))
6428 t->flags |= SN_ERR_SRVTO;
6429 if (!(t->flags & SN_FINST_MASK))
6430 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006431 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006432 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006433 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006434 if (may_dequeue_tasks(t->srv, t->proxy))
6435 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006436
willy tarreau036e1ce2005-12-17 13:46:33 +01006437 return 1;
6438 }
willy tarreau0f7af912005-12-17 12:21:26 +01006439 else if (rep->l == BUFSIZE) { /* no room to read more data */
6440 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
6441 FD_CLR(t->srv_fd, StaticReadEvent);
6442 tv_eternity(&t->srexpire);
6443 }
6444 }
6445 else {
6446 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6447 FD_SET(t->srv_fd, StaticReadEvent);
6448 if (t->proxy->srvtimeout)
6449 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6450 else
6451 tv_eternity(&t->srexpire);
6452 }
6453 }
6454 return 0;
6455 }
6456 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01006457 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01006458 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01006459 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 +01006460 write(1, trash, len);
6461 }
6462 return 0;
6463 }
6464 return 0;
6465}
6466
6467
willy tarreau5cbea6f2005-12-17 12:48:26 +01006468/* Processes the client and server jobs of a session task, then
6469 * puts it back to the wait queue in a clean state, or
6470 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01006471 * the time the task accepts to wait, or TIME_ETERNITY for
6472 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01006473 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006474int process_session(struct task *t) {
6475 struct session *s = t->context;
6476 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006477
willy tarreau5cbea6f2005-12-17 12:48:26 +01006478 do {
6479 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01006480 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006481 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01006482 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006483 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01006484 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006485 } while (fsm_resync);
6486
6487 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01006488 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006489 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01006490
willy tarreau5cbea6f2005-12-17 12:48:26 +01006491 tv_min(&min1, &s->crexpire, &s->cwexpire);
6492 tv_min(&min2, &s->srexpire, &s->swexpire);
6493 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01006494 tv_min(&t->expire, &min1, &min2);
6495
6496 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006497 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01006498
Willy TARREAU1cec83c2006-03-01 22:33:49 +01006499#ifdef DEBUG_FULL
6500 /* DEBUG code : this should never ever happen, otherwise it indicates
6501 * that a task still has something to do and will provoke a quick loop.
6502 */
6503 if (tv_remain2(&now, &t->expire) <= 0)
6504 exit(100);
6505#endif
6506
willy tarreaub952e1d2005-12-18 01:31:20 +01006507 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01006508 }
6509
willy tarreau5cbea6f2005-12-17 12:48:26 +01006510 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01006511 actconn--;
6512
willy tarreau982249e2005-12-18 00:57:06 +01006513 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01006514 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01006515 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 +01006516 write(1, trash, len);
6517 }
6518
willy tarreau750a4722005-12-17 13:21:24 +01006519 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01006520 if (s->rep != NULL)
6521 s->logs.bytes = s->rep->total;
6522
willy tarreau9fe663a2005-12-17 13:02:59 +01006523 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01006524 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01006525 sess_log(s);
6526
willy tarreau0f7af912005-12-17 12:21:26 +01006527 /* the task MUST not be in the run queue anymore */
6528 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006529 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01006530 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01006531 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006532}
6533
6534
willy tarreau2812edc2006-05-04 12:09:37 +02006535/* Sets server <s> down, notifies by all available means, recounts the
6536 * remaining servers on the proxy and transfers queued sessions whenever
6537 * possible to other servers.
6538 */
6539void set_server_down(struct server *s) {
6540 struct pendconn *pc, *pc_bck, *pc_end;
6541 struct session *sess;
6542 int xferred;
6543
6544 s->state &= ~SRV_RUNNING;
6545
6546 if (s->health == s->rise) {
6547 recount_servers(s->proxy);
6548 recalc_server_map(s->proxy);
6549
6550 /* we might have sessions queued on this server and waiting for
6551 * a connection. Those which are redispatchable will be queued
6552 * to another server or to the proxy itself.
6553 */
6554 xferred = 0;
6555 FOREACH_ITEM_SAFE(pc, pc_bck, &s->pendconns, pc_end, struct pendconn *, list) {
6556 sess = pc->sess;
6557 if ((sess->proxy->options & PR_O_REDISP)) {
6558 /* The REDISP option was specified. We will ignore
6559 * cookie and force to balance or use the dispatcher.
6560 */
6561 sess->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
6562 sess->srv = NULL; /* it's left to the dispatcher to choose a server */
6563 if ((sess->flags & SN_CK_MASK) == SN_CK_VALID) {
6564 sess->flags &= ~SN_CK_MASK;
6565 sess->flags |= SN_CK_DOWN;
6566 }
6567 pendconn_free(pc);
6568 task_wakeup(&rq, sess->task);
6569 xferred++;
6570 }
6571 }
6572
6573 sprintf(trash, "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s"
6574 " %d sessions active, %d requeued, %d remaining in queue.\n",
6575 s->state & SRV_BACKUP ? "Backup " : "",
6576 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6577 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6578 s->cur_sess, xferred, s->nbpend);
6579
willy tarreaubc2eda62006-05-04 15:16:23 +02006580 Warning("%s", trash);
6581 send_log(s->proxy, LOG_ALERT, "%s", trash);
willy tarreau2812edc2006-05-04 12:09:37 +02006582
6583 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
6584 Alert("Proxy %s has no server available !\n", s->proxy->id);
6585 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
6586 }
willy tarreaucb406512006-05-18 00:52:35 +02006587 s->down_trans++;
willy tarreau2812edc2006-05-04 12:09:37 +02006588 }
6589 s->health = 0; /* failure */
6590}
6591
6592
willy tarreau5cbea6f2005-12-17 12:48:26 +01006593
6594/*
6595 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01006596 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01006597 */
6598int process_chk(struct task *t) {
6599 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01006600 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01006601 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006602
willy tarreauef900ab2005-12-17 12:52:52 +01006603 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006604
willy tarreau25424f82006-03-19 19:37:48 +01006605 new_chk:
6606 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006607 if (fd < 0) { /* no check currently running */
6608 //fprintf(stderr, "process_chk: 2\n");
6609 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
6610 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006611 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006612 }
Willy TARREAU3759f982006-03-01 22:44:17 +01006613
6614 /* we don't send any health-checks when the proxy is stopped or when
6615 * the server should not be checked.
6616 */
6617 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01006618 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6619 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01006620 task_queue(t); /* restore t to its place in the task list */
6621 return tv_remain2(&now, &t->expire);
6622 }
6623
willy tarreau5cbea6f2005-12-17 12:48:26 +01006624 /* we'll initiate a new check */
6625 s->result = 0; /* no result yet */
6626 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006627 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01006628 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
6629 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
6630 //fprintf(stderr, "process_chk: 3\n");
6631
willy tarreaua41a8b42005-12-17 14:02:24 +01006632 /* we'll connect to the check port on the server */
6633 sa = s->addr;
6634 sa.sin_port = htons(s->check_port);
6635
willy tarreau0174f312005-12-18 01:02:42 +01006636 /* allow specific binding :
6637 * - server-specific at first
6638 * - proxy-specific next
6639 */
6640 if (s->state & SRV_BIND_SRC) {
6641 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
6642 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
6643 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
6644 s->proxy->id, s->id);
6645 s->result = -1;
6646 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006647 }
willy tarreau0174f312005-12-18 01:02:42 +01006648 else if (s->proxy->options & PR_O_BIND_SRC) {
6649 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
6650 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
6651 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
6652 s->proxy->id);
6653 s->result = -1;
6654 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006655 }
willy tarreau0174f312005-12-18 01:02:42 +01006656
6657 if (!s->result) {
6658 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
6659 /* OK, connection in progress or established */
6660
6661 //fprintf(stderr, "process_chk: 4\n");
6662
6663 s->curfd = fd; /* that's how we know a test is in progress ;-) */
6664 fdtab[fd].owner = t;
6665 fdtab[fd].read = &event_srv_chk_r;
6666 fdtab[fd].write = &event_srv_chk_w;
6667 fdtab[fd].state = FD_STCONN; /* connection in progress */
6668 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01006669#ifdef DEBUG_FULL
6670 assert (!FD_ISSET(fd, StaticReadEvent));
6671#endif
willy tarreau0174f312005-12-18 01:02:42 +01006672 fd_insert(fd);
6673 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
6674 tv_delayfrom(&t->expire, &now, s->inter);
6675 task_queue(t); /* restore t to its place in the task list */
6676 return tv_remain(&now, &t->expire);
6677 }
6678 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
6679 s->result = -1; /* a real error */
6680 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006681 }
6682 }
willy tarreau08dedbe2005-12-18 01:13:48 +01006683 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006684 }
6685
6686 if (!s->result) { /* nothing done */
6687 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01006688 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6689 tv_delayfrom(&t->expire, &t->expire, s->inter);
6690 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006691 }
6692
6693 /* here, we have seen a failure */
willy tarreaucb406512006-05-18 00:52:35 +02006694 if (s->health > s->rise) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006695 s->health--; /* still good */
willy tarreaucb406512006-05-18 00:52:35 +02006696 s->failed_checks++;
6697 }
willy tarreau2812edc2006-05-04 12:09:37 +02006698 else
6699 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006700
6701 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01006702 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01006703 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6704 tv_delayfrom(&t->expire, &t->expire, s->inter);
6705 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006706 }
6707 else {
6708 //fprintf(stderr, "process_chk: 8\n");
6709 /* there was a test running */
6710 if (s->result > 0) { /* good server detected */
6711 //fprintf(stderr, "process_chk: 9\n");
6712 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01006713 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02006714 s->state |= SRV_RUNNING;
6715
willy tarreau535ae7a2005-12-17 12:58:00 +01006716 if (s->health == s->rise) {
willy tarreaubc2eda62006-05-04 15:16:23 +02006717 int xferred;
6718
willy tarreau62084d42006-03-24 18:57:41 +01006719 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02006720 recalc_server_map(s->proxy);
willy tarreaubc2eda62006-05-04 15:16:23 +02006721
6722 /* check if we can handle some connections queued at the proxy. We
6723 * will take as many as we can handle.
6724 */
6725 for (xferred = 0; !s->maxconn || xferred < s->maxconn; xferred++) {
6726 struct session *sess;
6727 struct pendconn *p;
6728
6729 p = pendconn_from_px(s->proxy);
6730 if (!p)
6731 break;
6732 p->sess->srv = s;
6733 sess = p->sess;
6734 pendconn_free(p);
6735 task_wakeup(&rq, sess->task);
6736 }
6737
6738 sprintf(trash,
6739 "%sServer %s/%s is UP. %d active and %d backup servers online.%s"
6740 " %d sessions requeued, %d total in queue.\n",
6741 s->state & SRV_BACKUP ? "Backup " : "",
6742 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6743 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6744 xferred, s->nbpend);
6745
6746 Warning("%s", trash);
6747 send_log(s->proxy, LOG_NOTICE, "%s", trash);
willy tarreau535ae7a2005-12-17 12:58:00 +01006748 }
willy tarreauef900ab2005-12-17 12:52:52 +01006749
willy tarreaue47c8d72005-12-17 12:55:52 +01006750 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006751 }
willy tarreauef900ab2005-12-17 12:52:52 +01006752 s->curfd = -1; /* no check running anymore */
6753 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006754 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006755 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6756 tv_delayfrom(&t->expire, &t->expire, s->inter);
6757 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006758 }
6759 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
6760 //fprintf(stderr, "process_chk: 10\n");
6761 /* failure or timeout detected */
willy tarreaucb406512006-05-18 00:52:35 +02006762 if (s->health > s->rise) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006763 s->health--; /* still good */
willy tarreaucb406512006-05-18 00:52:35 +02006764 s->failed_checks++;
6765 }
willy tarreau2812edc2006-05-04 12:09:37 +02006766 else
6767 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006768 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01006769 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006770 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006771 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6772 tv_delayfrom(&t->expire, &t->expire, s->inter);
6773 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006774 }
6775 /* if result is 0 and there's no timeout, we have to wait again */
6776 }
6777 //fprintf(stderr, "process_chk: 11\n");
6778 s->result = 0;
6779 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006780 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01006781}
6782
6783
willy tarreau5cbea6f2005-12-17 12:48:26 +01006784
willy tarreau59a6cc22006-05-12 01:29:08 +02006785/*
6786 * Manages a server's connection queue. If woken up, will try to dequeue as
6787 * many pending sessions as possible, and wake them up. The task has nothing
6788 * else to do, so it always returns TIME_ETERNITY.
6789 */
6790int process_srv_queue(struct task *t) {
6791 struct server *s = (struct server*)t->context;
6792 struct proxy *p = s->proxy;
6793 int xferred;
6794
6795 /* First, check if we can handle some connections queued at the proxy. We
6796 * will take as many as we can handle.
6797 */
6798 for (xferred = 0; s->cur_sess + xferred < s->maxconn; xferred++) {
6799 struct session *sess;
6800
6801 sess = pendconn_get_next_sess(s, p);
6802 if (sess == NULL)
6803 break;
6804 task_wakeup(&rq, sess->task);
6805 }
6806
6807 return TIME_ETERNITY;
6808}
6809
willy tarreau0f7af912005-12-17 12:21:26 +01006810#if STATTIME > 0
6811int stats(void);
6812#endif
6813
6814/*
willy tarreau1c2ad212005-12-18 01:11:29 +01006815 * This does 4 things :
6816 * - wake up all expired tasks
6817 * - call all runnable tasks
6818 * - call maintain_proxies() to enable/disable the listeners
6819 * - return the delay till next event in ms, -1 = wait indefinitely
6820 * Note: this part should be rewritten with the O(ln(n)) scheduler.
6821 *
willy tarreau0f7af912005-12-17 12:21:26 +01006822 */
6823
willy tarreau1c2ad212005-12-18 01:11:29 +01006824int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01006825 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01006826 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006827 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01006828
willy tarreaub952e1d2005-12-18 01:31:20 +01006829 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01006830
willy tarreau1c2ad212005-12-18 01:11:29 +01006831 /* look for expired tasks and add them to the run queue.
6832 */
willy tarreau5e698ef2006-05-02 14:51:00 +02006833 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6834 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau1c2ad212005-12-18 01:11:29 +01006835 tnext = t->next;
6836 if (t->state & TASK_RUNNING)
6837 continue;
6838
willy tarreaub952e1d2005-12-18 01:31:20 +01006839 if (tv_iseternity(&t->expire))
6840 continue;
6841
willy tarreau1c2ad212005-12-18 01:11:29 +01006842 /* wakeup expired entries. It doesn't matter if they are
6843 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01006844 */
willy tarreaub952e1d2005-12-18 01:31:20 +01006845 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006846 task_wakeup(&rq, t);
6847 }
6848 else {
6849 /* first non-runnable task. Use its expiration date as an upper bound */
6850 int temp_time = tv_remain(&now, &t->expire);
6851 if (temp_time)
6852 next_time = temp_time;
6853 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006854 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006855 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006856
willy tarreau1c2ad212005-12-18 01:11:29 +01006857 /* process each task in the run queue now. Each task may be deleted
willy tarreau7feab592006-04-22 15:13:16 +02006858 * since we only use the run queue's head. Note that any task can be
6859 * woken up by any other task and it will be processed immediately
6860 * after as it will be queued on the run queue's head.
willy tarreau1c2ad212005-12-18 01:11:29 +01006861 */
willy tarreau7feab592006-04-22 15:13:16 +02006862 while ((t = rq) != NULL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006863 int temp_time;
willy tarreau7feab592006-04-22 15:13:16 +02006864
willy tarreau1c2ad212005-12-18 01:11:29 +01006865 task_sleep(&rq, t);
6866 temp_time = t->process(t);
6867 next_time = MINTIME(temp_time, next_time);
6868 }
6869
6870 /* maintain all proxies in a consistent state. This should quickly become a task */
6871 time2 = maintain_proxies();
6872 return MINTIME(time2, next_time);
6873}
6874
6875
6876#if defined(ENABLE_EPOLL)
6877
6878/*
6879 * Main epoll() loop.
6880 */
6881
6882/* does 3 actions :
6883 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6884 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6885 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6886 *
6887 * returns 0 if initialization failed, !0 otherwise.
6888 */
6889
6890int epoll_loop(int action) {
6891 int next_time;
6892 int status;
6893 int fd;
6894
6895 int fds, count;
6896 int pr, pw, sr, sw;
6897 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
6898 struct epoll_event ev;
6899
6900 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01006901 static struct epoll_event *epoll_events = NULL;
6902 static int epoll_fd;
6903
6904 if (action == POLL_LOOP_ACTION_INIT) {
6905 epoll_fd = epoll_create(global.maxsock + 1);
6906 if (epoll_fd < 0)
6907 return 0;
6908 else {
6909 epoll_events = (struct epoll_event*)
6910 calloc(1, sizeof(struct epoll_event) * global.maxsock);
6911 PrevReadEvent = (fd_set *)
6912 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6913 PrevWriteEvent = (fd_set *)
6914 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006915 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006916 return 1;
6917 }
6918 else if (action == POLL_LOOP_ACTION_CLEAN) {
6919 if (PrevWriteEvent) free(PrevWriteEvent);
6920 if (PrevReadEvent) free(PrevReadEvent);
6921 if (epoll_events) free(epoll_events);
6922 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01006923 epoll_fd = 0;
6924 return 1;
6925 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006926
willy tarreau1c2ad212005-12-18 01:11:29 +01006927 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006928
willy tarreau1c2ad212005-12-18 01:11:29 +01006929 tv_now(&now);
6930
6931 while (1) {
6932 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01006933
6934 /* stop when there's no connection left and we don't allow them anymore */
6935 if (!actconn && listeners == 0)
6936 break;
6937
willy tarreau0f7af912005-12-17 12:21:26 +01006938#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01006939 {
6940 int time2;
6941 time2 = stats();
6942 next_time = MINTIME(time2, next_time);
6943 }
willy tarreau0f7af912005-12-17 12:21:26 +01006944#endif
6945
willy tarreau1c2ad212005-12-18 01:11:29 +01006946 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6947
6948 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
6949 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
6950
6951 if ((ro^rn) | (wo^wn)) {
6952 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6953#define FDSETS_ARE_INT_ALIGNED
6954#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01006955
willy tarreauad90a0c2005-12-18 01:09:15 +01006956#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6957#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01006958 pr = (ro >> count) & 1;
6959 pw = (wo >> count) & 1;
6960 sr = (rn >> count) & 1;
6961 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01006962#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006963 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
6964 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
6965 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6966 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01006967#endif
6968#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006969 pr = FD_ISSET(fd, PrevReadEvent);
6970 pw = FD_ISSET(fd, PrevWriteEvent);
6971 sr = FD_ISSET(fd, StaticReadEvent);
6972 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01006973#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01006974 if (!((sr^pr) | (sw^pw)))
6975 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01006976
willy tarreau1c2ad212005-12-18 01:11:29 +01006977 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
6978 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01006979
willy tarreaub952e1d2005-12-18 01:31:20 +01006980#ifdef EPOLL_CTL_MOD_WORKAROUND
6981 /* I encountered a rarely reproducible problem with
6982 * EPOLL_CTL_MOD where a modified FD (systematically
6983 * the one in epoll_events[0], fd#7) would sometimes
6984 * be set EPOLL_OUT while asked for a read ! This is
6985 * with the 2.4 epoll patch. The workaround is to
6986 * delete then recreate in case of modification.
6987 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
6988 * nor RHEL kernels.
6989 */
6990
6991 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
6992 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
6993
6994 if ((sr | sw))
6995 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
6996#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006997 if ((pr | pw)) {
6998 /* the file-descriptor already exists... */
6999 if ((sr | sw)) {
7000 /* ...and it will still exist */
7001 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
7002 // perror("epoll_ctl(MOD)");
7003 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01007004 }
7005 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01007006 /* ...and it will be removed */
7007 if (fdtab[fd].state != FD_STCLOSE &&
7008 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
7009 // perror("epoll_ctl(DEL)");
7010 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01007011 }
7012 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007013 } else {
7014 /* the file-descriptor did not exist, let's add it */
7015 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
7016 // perror("epoll_ctl(ADD)");
7017 // exit(1);
7018 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007019 }
willy tarreaub952e1d2005-12-18 01:31:20 +01007020#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01007021 }
7022 ((int*)PrevReadEvent)[fds] = rn;
7023 ((int*)PrevWriteEvent)[fds] = wn;
7024 }
7025 }
7026
7027 /* now let's wait for events */
7028 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
7029 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01007030
willy tarreau1c2ad212005-12-18 01:11:29 +01007031 for (count = 0; count < status; count++) {
7032 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01007033
7034 if (FD_ISSET(fd, StaticReadEvent)) {
7035 if (fdtab[fd].state == FD_STCLOSE)
7036 continue;
7037 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
7038 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007039 }
willy tarreau05be12b2006-03-19 19:35:00 +01007040
7041 if (FD_ISSET(fd, StaticWriteEvent)) {
7042 if (fdtab[fd].state == FD_STCLOSE)
7043 continue;
7044 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
7045 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007046 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007047 }
7048 }
7049 return 1;
7050}
7051#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01007052
willy tarreauad90a0c2005-12-18 01:09:15 +01007053
willy tarreau5cbea6f2005-12-17 12:48:26 +01007054
willy tarreau1c2ad212005-12-18 01:11:29 +01007055#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01007056
willy tarreau1c2ad212005-12-18 01:11:29 +01007057/*
7058 * Main poll() loop.
7059 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007060
willy tarreau1c2ad212005-12-18 01:11:29 +01007061/* does 3 actions :
7062 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
7063 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
7064 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
7065 *
7066 * returns 0 if initialization failed, !0 otherwise.
7067 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007068
willy tarreau1c2ad212005-12-18 01:11:29 +01007069int poll_loop(int action) {
7070 int next_time;
7071 int status;
7072 int fd, nbfd;
7073
7074 int fds, count;
7075 int sr, sw;
7076 unsigned rn, wn; /* read new, write new */
7077
7078 /* private data */
7079 static struct pollfd *poll_events = NULL;
7080
7081 if (action == POLL_LOOP_ACTION_INIT) {
7082 poll_events = (struct pollfd*)
7083 calloc(1, sizeof(struct pollfd) * global.maxsock);
7084 return 1;
7085 }
7086 else if (action == POLL_LOOP_ACTION_CLEAN) {
7087 if (poll_events)
7088 free(poll_events);
7089 return 1;
7090 }
7091
7092 /* OK, it's POLL_LOOP_ACTION_RUN */
7093
7094 tv_now(&now);
7095
7096 while (1) {
7097 next_time = process_runnable_tasks();
7098
7099 /* stop when there's no connection left and we don't allow them anymore */
7100 if (!actconn && listeners == 0)
7101 break;
7102
7103#if STATTIME > 0
7104 {
7105 int time2;
7106 time2 = stats();
7107 next_time = MINTIME(time2, next_time);
7108 }
7109#endif
7110
7111
7112 nbfd = 0;
7113 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
7114
7115 rn = ((int*)StaticReadEvent)[fds];
7116 wn = ((int*)StaticWriteEvent)[fds];
7117
7118 if ((rn|wn)) {
7119 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
7120#define FDSETS_ARE_INT_ALIGNED
7121#ifdef FDSETS_ARE_INT_ALIGNED
7122
7123#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
7124#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
7125 sr = (rn >> count) & 1;
7126 sw = (wn >> count) & 1;
7127#else
7128 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
7129 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
7130#endif
7131#else
7132 sr = FD_ISSET(fd, StaticReadEvent);
7133 sw = FD_ISSET(fd, StaticWriteEvent);
7134#endif
7135 if ((sr|sw)) {
7136 poll_events[nbfd].fd = fd;
7137 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
7138 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01007139 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007140 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007141 }
7142 }
7143
7144 /* now let's wait for events */
7145 status = poll(poll_events, nbfd, next_time);
7146 tv_now(&now);
7147
7148 for (count = 0; status > 0 && count < nbfd; count++) {
7149 fd = poll_events[count].fd;
7150
willy tarreau606788e2006-05-21 16:26:20 +02007151 if (!(poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP )))
willy tarreau1c2ad212005-12-18 01:11:29 +01007152 continue;
7153
7154 /* ok, we found one active fd */
7155 status--;
7156
willy tarreau05be12b2006-03-19 19:35:00 +01007157 if (FD_ISSET(fd, StaticReadEvent)) {
7158 if (fdtab[fd].state == FD_STCLOSE)
7159 continue;
7160 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
7161 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007162 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007163
willy tarreau05be12b2006-03-19 19:35:00 +01007164 if (FD_ISSET(fd, StaticWriteEvent)) {
7165 if (fdtab[fd].state == FD_STCLOSE)
7166 continue;
7167 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
7168 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007169 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007170 }
7171 }
7172 return 1;
7173}
willy tarreauad90a0c2005-12-18 01:09:15 +01007174#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01007175
willy tarreauad90a0c2005-12-18 01:09:15 +01007176
willy tarreauad90a0c2005-12-18 01:09:15 +01007177
willy tarreau1c2ad212005-12-18 01:11:29 +01007178/*
7179 * Main select() loop.
7180 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007181
willy tarreau1c2ad212005-12-18 01:11:29 +01007182/* does 3 actions :
7183 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
7184 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
7185 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
7186 *
7187 * returns 0 if initialization failed, !0 otherwise.
7188 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007189
willy tarreauad90a0c2005-12-18 01:09:15 +01007190
willy tarreau1c2ad212005-12-18 01:11:29 +01007191int select_loop(int action) {
7192 int next_time;
7193 int status;
7194 int fd,i;
7195 struct timeval delta;
7196 int readnotnull, writenotnull;
7197 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01007198
willy tarreau1c2ad212005-12-18 01:11:29 +01007199 if (action == POLL_LOOP_ACTION_INIT) {
7200 ReadEvent = (fd_set *)
7201 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
7202 WriteEvent = (fd_set *)
7203 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
7204 return 1;
7205 }
7206 else if (action == POLL_LOOP_ACTION_CLEAN) {
7207 if (WriteEvent) free(WriteEvent);
7208 if (ReadEvent) free(ReadEvent);
7209 return 1;
7210 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007211
willy tarreau1c2ad212005-12-18 01:11:29 +01007212 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01007213
willy tarreau1c2ad212005-12-18 01:11:29 +01007214 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01007215
willy tarreau1c2ad212005-12-18 01:11:29 +01007216 while (1) {
7217 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01007218
willy tarreau1c2ad212005-12-18 01:11:29 +01007219 /* stop when there's no connection left and we don't allow them anymore */
7220 if (!actconn && listeners == 0)
7221 break;
7222
7223#if STATTIME > 0
7224 {
7225 int time2;
7226 time2 = stats();
7227 next_time = MINTIME(time2, next_time);
7228 }
7229#endif
7230
willy tarreau1c2ad212005-12-18 01:11:29 +01007231 if (next_time > 0) { /* FIXME */
7232 /* Convert to timeval */
7233 /* to avoid eventual select loops due to timer precision */
7234 next_time += SCHEDULER_RESOLUTION;
7235 delta.tv_sec = next_time / 1000;
7236 delta.tv_usec = (next_time % 1000) * 1000;
7237 }
7238 else if (next_time == 0) { /* allow select to return immediately when needed */
7239 delta.tv_sec = delta.tv_usec = 0;
7240 }
7241
7242
7243 /* let's restore fdset state */
7244
7245 readnotnull = 0; writenotnull = 0;
7246 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
7247 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
7248 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
7249 }
7250
7251 // /* just a verification code, needs to be removed for performance */
7252 // for (i=0; i<maxfd; i++) {
7253 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
7254 // abort();
7255 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
7256 // abort();
7257 //
7258 // }
7259
7260 status = select(maxfd,
7261 readnotnull ? ReadEvent : NULL,
7262 writenotnull ? WriteEvent : NULL,
7263 NULL,
7264 (next_time >= 0) ? &delta : NULL);
7265
7266 /* this is an experiment on the separation of the select work */
7267 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
7268 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
7269
7270 tv_now(&now);
7271
7272 if (status > 0) { /* must proceed with events */
7273
7274 int fds;
7275 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01007276
willy tarreau1c2ad212005-12-18 01:11:29 +01007277 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
7278 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
7279 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
7280
7281 /* if we specify read first, the accepts and zero reads will be
7282 * seen first. Moreover, system buffers will be flushed faster.
7283 */
willy tarreau05be12b2006-03-19 19:35:00 +01007284 if (FD_ISSET(fd, ReadEvent)) {
7285 if (fdtab[fd].state == FD_STCLOSE)
7286 continue;
7287 fdtab[fd].read(fd);
7288 }
willy tarreau64a3cc32005-12-18 01:13:11 +01007289
willy tarreau05be12b2006-03-19 19:35:00 +01007290 if (FD_ISSET(fd, WriteEvent)) {
7291 if (fdtab[fd].state == FD_STCLOSE)
7292 continue;
7293 fdtab[fd].write(fd);
7294 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007295 }
7296 }
7297 else {
7298 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01007299 }
willy tarreau0f7af912005-12-17 12:21:26 +01007300 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007301 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01007302}
7303
7304
7305#if STATTIME > 0
7306/*
7307 * Display proxy statistics regularly. It is designed to be called from the
7308 * select_loop().
7309 */
7310int stats(void) {
7311 static int lines;
7312 static struct timeval nextevt;
7313 static struct timeval lastevt;
7314 static struct timeval starttime = {0,0};
7315 unsigned long totaltime, deltatime;
7316 int ret;
7317
willy tarreau750a4722005-12-17 13:21:24 +01007318 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01007319 deltatime = (tv_diff(&lastevt, &now)?:1);
7320 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01007321
willy tarreau9fe663a2005-12-17 13:02:59 +01007322 if (global.mode & MODE_STATS) {
7323 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007324 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007325 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
7326 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007327 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01007328 actconn, totalconn,
7329 stats_tsk_new, stats_tsk_good,
7330 stats_tsk_left, stats_tsk_right,
7331 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
7332 }
7333 }
7334
7335 tv_delayfrom(&nextevt, &now, STATTIME);
7336
7337 lastevt=now;
7338 }
7339 ret = tv_remain(&now, &nextevt);
7340 return ret;
7341}
7342#endif
7343
7344
7345/*
7346 * this function enables proxies when there are enough free sessions,
7347 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01007348 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01007349 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01007350 */
7351static int maintain_proxies(void) {
7352 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01007353 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007354 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01007355
7356 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01007357 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01007358
7359 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01007360 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01007361 while (p) {
7362 if (p->nbconn < p->maxconn) {
7363 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007364 for (l = p->listen; l != NULL; l = l->next) {
7365 FD_SET(l->fd, StaticReadEvent);
7366 }
willy tarreau0f7af912005-12-17 12:21:26 +01007367 p->state = PR_STRUN;
7368 }
7369 }
7370 else {
7371 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007372 for (l = p->listen; l != NULL; l = l->next) {
7373 FD_CLR(l->fd, StaticReadEvent);
7374 }
willy tarreau0f7af912005-12-17 12:21:26 +01007375 p->state = PR_STIDLE;
7376 }
7377 }
7378 p = p->next;
7379 }
7380 }
7381 else { /* block all proxies */
7382 while (p) {
7383 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007384 for (l = p->listen; l != NULL; l = l->next) {
7385 FD_CLR(l->fd, StaticReadEvent);
7386 }
willy tarreau0f7af912005-12-17 12:21:26 +01007387 p->state = PR_STIDLE;
7388 }
7389 p = p->next;
7390 }
7391 }
7392
willy tarreau5cbea6f2005-12-17 12:48:26 +01007393 if (stopping) {
7394 p = proxy;
7395 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007396 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007397 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01007398 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007399 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01007400 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01007401 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01007402
willy tarreaua41a8b42005-12-17 14:02:24 +01007403 for (l = p->listen; l != NULL; l = l->next) {
7404 fd_delete(l->fd);
7405 listeners--;
7406 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007407 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007408 }
7409 else {
7410 tleft = MINTIME(t, tleft);
7411 }
7412 }
7413 p = p->next;
7414 }
7415 }
7416 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01007417}
7418
7419/*
7420 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01007421 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
7422 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01007423 */
7424static void soft_stop(void) {
7425 struct proxy *p;
7426
7427 stopping = 1;
7428 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007429 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01007430 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01007431 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01007432 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01007433 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01007434 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01007435 }
willy tarreau0f7af912005-12-17 12:21:26 +01007436 p = p->next;
7437 }
7438}
7439
willy tarreaufac1a862006-05-21 10:20:28 +02007440/*
7441 * Linux unbinds the listen socket after a SHUT_RD, and ignores SHUT_WR.
7442 * Solaris refuses either shutdown().
7443 * OpenBSD ignores SHUT_RD but closes upon SHUT_WR and refuses to rebind.
7444 * So a common validation path involves SHUT_WR && listen && SHUT_RD.
7445 * If disabling at least one listener returns an error, then the proxy
7446 * state is set to PR_STERROR because we don't know how to resume from this.
7447 */
willy tarreaudbd3bef2006-01-20 19:35:18 +01007448static void pause_proxy(struct proxy *p) {
7449 struct listener *l;
7450 for (l = p->listen; l != NULL; l = l->next) {
willy tarreaufac1a862006-05-21 10:20:28 +02007451 if (shutdown(l->fd, SHUT_WR) == 0 && listen(l->fd, p->maxconn) == 0 &&
7452 shutdown(l->fd, SHUT_RD) == 0) {
Willy TARREAU007aa462006-05-14 09:55:23 +02007453 FD_CLR(l->fd, StaticReadEvent);
willy tarreaufac1a862006-05-21 10:20:28 +02007454 if (p->state != PR_STERROR)
7455 p->state = PR_STPAUSED;
Willy TARREAU007aa462006-05-14 09:55:23 +02007456 }
willy tarreaufac1a862006-05-21 10:20:28 +02007457 else
7458 p->state = PR_STERROR;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007459 }
7460}
7461
7462/*
7463 * This function temporarily disables listening so that another new instance
7464 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01007465 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01007466 * the proxy, or a SIGTTIN can be sent to listen again.
7467 */
7468static void pause_proxies(void) {
Willy TARREAU007aa462006-05-14 09:55:23 +02007469 int err;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007470 struct proxy *p;
7471
Willy TARREAU007aa462006-05-14 09:55:23 +02007472 err = 0;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007473 p = proxy;
7474 tv_now(&now); /* else, the old time before select will be used */
7475 while (p) {
willy tarreaufac1a862006-05-21 10:20:28 +02007476 if (p->state != PR_STERROR && p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007477 Warning("Pausing proxy %s.\n", p->id);
7478 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
7479 pause_proxy(p);
Willy TARREAU007aa462006-05-14 09:55:23 +02007480 if (p->state != PR_STPAUSED) {
7481 err |= 1;
7482 Warning("Proxy %s failed to enter pause mode.\n", p->id);
7483 send_log(p, LOG_WARNING, "Proxy %s failed to enter pause mode.\n", p->id);
7484 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007485 }
7486 p = p->next;
7487 }
Willy TARREAU007aa462006-05-14 09:55:23 +02007488 if (err) {
7489 Warning("Some proxies refused to pause, performing soft stop now.\n");
7490 send_log(p, LOG_WARNING, "Some proxies refused to pause, performing soft stop now.\n");
7491 soft_stop();
7492 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007493}
7494
7495
7496/*
7497 * This function reactivates listening. This can be used after a call to
7498 * sig_pause(), for example when a new instance has failed starting up.
7499 * It is designed to be called upon reception of a SIGTTIN.
7500 */
7501static void listen_proxies(void) {
7502 struct proxy *p;
7503 struct listener *l;
7504
7505 p = proxy;
7506 tv_now(&now); /* else, the old time before select will be used */
7507 while (p) {
7508 if (p->state == PR_STPAUSED) {
7509 Warning("Enabling proxy %s.\n", p->id);
7510 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
7511
7512 for (l = p->listen; l != NULL; l = l->next) {
7513 if (listen(l->fd, p->maxconn) == 0) {
7514 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
7515 FD_SET(l->fd, StaticReadEvent);
7516 p->state = PR_STRUN;
7517 }
7518 else
7519 p->state = PR_STIDLE;
7520 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01007521 int port;
7522
7523 if (l->addr.ss_family == AF_INET6)
7524 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
7525 else
7526 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
7527
willy tarreaudbd3bef2006-01-20 19:35:18 +01007528 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01007529 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01007530 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01007531 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01007532 /* Another port might have been enabled. Let's stop everything. */
7533 pause_proxy(p);
7534 break;
7535 }
7536 }
7537 }
7538 p = p->next;
7539 }
7540}
7541
7542
willy tarreau0f7af912005-12-17 12:21:26 +01007543/*
7544 * upon SIGUSR1, let's have a soft stop.
7545 */
7546void sig_soft_stop(int sig) {
7547 soft_stop();
7548 signal(sig, SIG_IGN);
7549}
7550
willy tarreaudbd3bef2006-01-20 19:35:18 +01007551/*
7552 * upon SIGTTOU, we pause everything
7553 */
7554void sig_pause(int sig) {
7555 pause_proxies();
7556 signal(sig, sig_pause);
7557}
willy tarreau0f7af912005-12-17 12:21:26 +01007558
willy tarreau8337c6b2005-12-17 13:41:01 +01007559/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01007560 * upon SIGTTIN, let's have a soft stop.
7561 */
7562void sig_listen(int sig) {
7563 listen_proxies();
7564 signal(sig, sig_listen);
7565}
7566
7567/*
willy tarreau8337c6b2005-12-17 13:41:01 +01007568 * this function dumps every server's state when the process receives SIGHUP.
7569 */
7570void sig_dump_state(int sig) {
7571 struct proxy *p = proxy;
7572
7573 Warning("SIGHUP received, dumping servers states.\n");
7574 while (p) {
7575 struct server *s = p->srv;
7576
willy tarreau4632c212006-05-02 23:32:51 +02007577 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01007578 while (s) {
willy tarreau4632c212006-05-02 23:32:51 +02007579 snprintf(trash, sizeof(trash),
7580 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %d tot.",
7581 p->id, s->id,
7582 (s->state & SRV_RUNNING) ? "UP" : "DOWN",
7583 s->cur_sess, s->nbpend, s->cum_sess);
willy tarreau14b4d432006-04-07 18:23:29 +02007584 Warning("%s\n", trash);
7585 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01007586 s = s->next;
7587 }
willy tarreaudd07e972005-12-18 00:48:48 +01007588
willy tarreau62084d42006-03-24 18:57:41 +01007589 if (p->srv_act == 0) {
willy tarreau4632c212006-05-02 23:32:51 +02007590 snprintf(trash, sizeof(trash),
7591 "SIGHUP: Proxy %s %s ! Conn: %d act, %d pend (%d unass), %d tot.",
7592 p->id,
7593 (p->srv_bck) ? "is running on backup servers" : "has no server available",
7594 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02007595 } else {
7596 snprintf(trash, sizeof(trash),
willy tarreau4632c212006-05-02 23:32:51 +02007597 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
7598 " Conn: %d act, %d pend (%d unass), %d tot.",
7599 p->id, p->srv_act, p->srv_bck,
7600 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02007601 }
7602 Warning("%s\n", trash);
7603 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01007604
willy tarreau8337c6b2005-12-17 13:41:01 +01007605 p = p->next;
7606 }
7607 signal(sig, sig_dump_state);
7608}
7609
willy tarreau0f7af912005-12-17 12:21:26 +01007610void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007611 struct task *t, *tnext;
7612 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01007613
willy tarreau5e698ef2006-05-02 14:51:00 +02007614 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
7615 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007616 tnext = t->next;
7617 s = t->context;
7618 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
7619 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
7620 "req=%d, rep=%d, clifd=%d\n",
7621 s, tv_remain(&now, &t->expire),
7622 s->cli_state,
7623 s->srv_state,
7624 FD_ISSET(s->cli_fd, StaticReadEvent),
7625 FD_ISSET(s->cli_fd, StaticWriteEvent),
7626 FD_ISSET(s->srv_fd, StaticReadEvent),
7627 FD_ISSET(s->srv_fd, StaticWriteEvent),
7628 s->req->l, s->rep?s->rep->l:0, s->cli_fd
7629 );
willy tarreau0f7af912005-12-17 12:21:26 +01007630 }
willy tarreau12350152005-12-18 01:03:27 +01007631}
7632
willy tarreau64a3cc32005-12-18 01:13:11 +01007633#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01007634static void fast_stop(void)
7635{
7636 struct proxy *p;
7637 p = proxy;
7638 while (p) {
7639 p->grace = 0;
7640 p = p->next;
7641 }
7642 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01007643}
7644
willy tarreau12350152005-12-18 01:03:27 +01007645void sig_int(int sig) {
7646 /* This would normally be a hard stop,
7647 but we want to be sure about deallocation,
7648 and so on, so we do a soft stop with
7649 0 GRACE time
7650 */
7651 fast_stop();
7652 /* If we are killed twice, we decide to die*/
7653 signal(sig, SIG_DFL);
7654}
7655
7656void sig_term(int sig) {
7657 /* This would normally be a hard stop,
7658 but we want to be sure about deallocation,
7659 and so on, so we do a soft stop with
7660 0 GRACE time
7661 */
7662 fast_stop();
7663 /* If we are killed twice, we decide to die*/
7664 signal(sig, SIG_DFL);
7665}
willy tarreau64a3cc32005-12-18 01:13:11 +01007666#endif
willy tarreau12350152005-12-18 01:03:27 +01007667
willy tarreauc1f47532005-12-18 01:08:26 +01007668/* returns the pointer to an error in the replacement string, or NULL if OK */
7669char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01007670 struct hdr_exp *exp;
7671
willy tarreauc1f47532005-12-18 01:08:26 +01007672 if (replace != NULL) {
7673 char *err;
7674 err = check_replace_string(replace);
7675 if (err)
7676 return err;
7677 }
7678
willy tarreaue39cd132005-12-17 13:00:18 +01007679 while (*head != NULL)
7680 head = &(*head)->next;
7681
7682 exp = calloc(1, sizeof(struct hdr_exp));
7683
7684 exp->preg = preg;
7685 exp->replace = replace;
7686 exp->action = action;
7687 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01007688
7689 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007690}
7691
willy tarreau9fe663a2005-12-17 13:02:59 +01007692
willy tarreau0f7af912005-12-17 12:21:26 +01007693/*
willy tarreau9fe663a2005-12-17 13:02:59 +01007694 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01007695 */
willy tarreau9fe663a2005-12-17 13:02:59 +01007696int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01007697
willy tarreau9fe663a2005-12-17 13:02:59 +01007698 if (!strcmp(args[0], "global")) { /* new section */
7699 /* no option, nothing special to do */
7700 return 0;
7701 }
7702 else if (!strcmp(args[0], "daemon")) {
7703 global.mode |= MODE_DAEMON;
7704 }
7705 else if (!strcmp(args[0], "debug")) {
7706 global.mode |= MODE_DEBUG;
7707 }
willy tarreau64a3cc32005-12-18 01:13:11 +01007708 else if (!strcmp(args[0], "noepoll")) {
7709 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
7710 }
7711 else if (!strcmp(args[0], "nopoll")) {
7712 cfg_polling_mechanism &= ~POLL_USE_POLL;
7713 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007714 else if (!strcmp(args[0], "quiet")) {
7715 global.mode |= MODE_QUIET;
7716 }
7717 else if (!strcmp(args[0], "stats")) {
7718 global.mode |= MODE_STATS;
7719 }
7720 else if (!strcmp(args[0], "uid")) {
7721 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007722 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007723 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007724 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007725 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007726 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007727 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007728 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007729 global.uid = atol(args[1]);
7730 }
7731 else if (!strcmp(args[0], "gid")) {
7732 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007733 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007734 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007735 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007736 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007737 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007738 return -1;
7739 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007740 global.gid = atol(args[1]);
7741 }
7742 else if (!strcmp(args[0], "nbproc")) {
7743 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007744 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007745 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007746 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007747 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007748 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007749 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007750 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007751 global.nbproc = atol(args[1]);
7752 }
7753 else if (!strcmp(args[0], "maxconn")) {
7754 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007755 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007756 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007757 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007758 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007759 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007760 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007761 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007762 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01007763#ifdef SYSTEM_MAXCONN
7764 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
7765 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);
7766 global.maxconn = DEFAULT_MAXCONN;
7767 }
7768#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01007769 }
willy tarreaub1285d52005-12-18 01:20:14 +01007770 else if (!strcmp(args[0], "ulimit-n")) {
7771 if (global.rlimit_nofile != 0) {
7772 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7773 return 0;
7774 }
7775 if (*(args[1]) == 0) {
7776 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
7777 return -1;
7778 }
7779 global.rlimit_nofile = atol(args[1]);
7780 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007781 else if (!strcmp(args[0], "chroot")) {
7782 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007783 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007784 return 0;
7785 }
7786 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007787 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007788 return -1;
7789 }
7790 global.chroot = strdup(args[1]);
7791 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007792 else if (!strcmp(args[0], "pidfile")) {
7793 if (global.pidfile != NULL) {
7794 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7795 return 0;
7796 }
7797 if (*(args[1]) == 0) {
7798 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
7799 return -1;
7800 }
7801 global.pidfile = strdup(args[1]);
7802 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007803 else if (!strcmp(args[0], "log")) { /* syslog server address */
7804 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01007805 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007806
7807 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007808 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007809 return -1;
7810 }
7811
7812 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7813 if (!strcmp(log_facilities[facility], args[2]))
7814 break;
7815
7816 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007817 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007818 exit(1);
7819 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007820
7821 level = 7; /* max syslog level = debug */
7822 if (*(args[3])) {
7823 while (level >= 0 && strcmp(log_levels[level], args[3]))
7824 level--;
7825 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007826 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007827 exit(1);
7828 }
7829 }
7830
willy tarreau9fe663a2005-12-17 13:02:59 +01007831 sa = str2sa(args[1]);
7832 if (!sa->sin_port)
7833 sa->sin_port = htons(SYSLOG_PORT);
7834
7835 if (global.logfac1 == -1) {
7836 global.logsrv1 = *sa;
7837 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007838 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007839 }
7840 else if (global.logfac2 == -1) {
7841 global.logsrv2 = *sa;
7842 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007843 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007844 }
7845 else {
7846 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
7847 return -1;
7848 }
7849
7850 }
7851 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007852 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01007853 return -1;
7854 }
7855 return 0;
7856}
7857
7858
willy tarreaua41a8b42005-12-17 14:02:24 +01007859void init_default_instance() {
7860 memset(&defproxy, 0, sizeof(defproxy));
7861 defproxy.mode = PR_MODE_TCP;
7862 defproxy.state = PR_STNEW;
7863 defproxy.maxconn = cfg_maxpconn;
7864 defproxy.conn_retries = CONN_RETRIES;
7865 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
7866}
7867
willy tarreau9fe663a2005-12-17 13:02:59 +01007868/*
7869 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
7870 */
7871int cfg_parse_listen(char *file, int linenum, char **args) {
7872 static struct proxy *curproxy = NULL;
7873 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01007874 char *err;
willy tarreau12350152005-12-18 01:03:27 +01007875 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01007876
7877 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01007878 if (!*args[1]) {
7879 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
7880 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007881 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007882 return -1;
7883 }
7884
7885 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007886 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007887 return -1;
7888 }
willy tarreaudfece232006-05-02 00:19:57 +02007889
willy tarreau9fe663a2005-12-17 13:02:59 +01007890 curproxy->next = proxy;
7891 proxy = curproxy;
willy tarreaudfece232006-05-02 00:19:57 +02007892 LIST_INIT(&curproxy->pendconns);
7893
willy tarreau9fe663a2005-12-17 13:02:59 +01007894 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01007895
7896 /* parse the listener address if any */
7897 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007898 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007899 if (!curproxy->listen)
7900 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007901 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01007902 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007903
willy tarreau9fe663a2005-12-17 13:02:59 +01007904 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01007905 curproxy->state = defproxy.state;
7906 curproxy->maxconn = defproxy.maxconn;
7907 curproxy->conn_retries = defproxy.conn_retries;
7908 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007909
7910 if (defproxy.check_req)
7911 curproxy->check_req = strdup(defproxy.check_req);
7912 curproxy->check_len = defproxy.check_len;
7913
7914 if (defproxy.cookie_name)
7915 curproxy->cookie_name = strdup(defproxy.cookie_name);
7916 curproxy->cookie_len = defproxy.cookie_len;
7917
7918 if (defproxy.capture_name)
7919 curproxy->capture_name = strdup(defproxy.capture_name);
7920 curproxy->capture_namelen = defproxy.capture_namelen;
7921 curproxy->capture_len = defproxy.capture_len;
7922
7923 if (defproxy.errmsg.msg400)
7924 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
7925 curproxy->errmsg.len400 = defproxy.errmsg.len400;
7926
7927 if (defproxy.errmsg.msg403)
7928 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
7929 curproxy->errmsg.len403 = defproxy.errmsg.len403;
7930
7931 if (defproxy.errmsg.msg408)
7932 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
7933 curproxy->errmsg.len408 = defproxy.errmsg.len408;
7934
7935 if (defproxy.errmsg.msg500)
7936 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
7937 curproxy->errmsg.len500 = defproxy.errmsg.len500;
7938
7939 if (defproxy.errmsg.msg502)
7940 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
7941 curproxy->errmsg.len502 = defproxy.errmsg.len502;
7942
7943 if (defproxy.errmsg.msg503)
7944 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
7945 curproxy->errmsg.len503 = defproxy.errmsg.len503;
7946
7947 if (defproxy.errmsg.msg504)
7948 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
7949 curproxy->errmsg.len504 = defproxy.errmsg.len504;
7950
willy tarreaua41a8b42005-12-17 14:02:24 +01007951 curproxy->clitimeout = defproxy.clitimeout;
7952 curproxy->contimeout = defproxy.contimeout;
7953 curproxy->srvtimeout = defproxy.srvtimeout;
7954 curproxy->mode = defproxy.mode;
7955 curproxy->logfac1 = defproxy.logfac1;
7956 curproxy->logsrv1 = defproxy.logsrv1;
7957 curproxy->loglev1 = defproxy.loglev1;
7958 curproxy->logfac2 = defproxy.logfac2;
7959 curproxy->logsrv2 = defproxy.logsrv2;
7960 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01007961 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01007962 curproxy->grace = defproxy.grace;
willy tarreau1f431b52006-05-21 14:46:15 +02007963 curproxy->uri_auth = defproxy.uri_auth;
willy tarreaua41a8b42005-12-17 14:02:24 +01007964 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01007965 curproxy->mon_net = defproxy.mon_net;
7966 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01007967 return 0;
7968 }
7969 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007970 /* some variables may have already been initialized earlier */
7971 if (defproxy.check_req) free(defproxy.check_req);
7972 if (defproxy.cookie_name) free(defproxy.cookie_name);
7973 if (defproxy.capture_name) free(defproxy.capture_name);
7974 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
7975 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
7976 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
7977 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
7978 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
7979 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
7980 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
willy tarreau1f431b52006-05-21 14:46:15 +02007981 /* we cannot free uri_auth because it might already be used */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007982 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01007983 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01007984 return 0;
7985 }
7986 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007987 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007988 return -1;
7989 }
7990
willy tarreaua41a8b42005-12-17 14:02:24 +01007991 if (!strcmp(args[0], "bind")) { /* new listen addresses */
7992 if (curproxy == &defproxy) {
7993 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7994 return -1;
7995 }
7996
7997 if (strchr(args[1], ':') == NULL) {
7998 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
7999 file, linenum, args[0]);
8000 return -1;
8001 }
8002 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01008003 if (!curproxy->listen)
8004 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008005 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01008006 return 0;
8007 }
willy tarreaub1285d52005-12-18 01:20:14 +01008008 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
8009 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
8010 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
8011 file, linenum, args[0]);
8012 return -1;
8013 }
8014 /* flush useless bits */
8015 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
8016 return 0;
8017 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008018 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01008019 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
8020 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
8021 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
8022 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008023 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008024 return -1;
8025 }
8026 }
8027 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01008028 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01008029 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008030 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
8031 curproxy->state = PR_STNEW;
8032 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008033 else if (!strcmp(args[0], "cookie")) { /* cookie name */
8034 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01008035// if (curproxy == &defproxy) {
8036// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8037// return -1;
8038// }
willy tarreaua41a8b42005-12-17 14:02:24 +01008039
willy tarreau9fe663a2005-12-17 13:02:59 +01008040 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008041// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
8042// file, linenum);
8043// return 0;
8044 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01008045 }
8046
8047 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008048 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
8049 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008050 return -1;
8051 }
8052 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008053 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01008054
8055 cur_arg = 2;
8056 while (*(args[cur_arg])) {
8057 if (!strcmp(args[cur_arg], "rewrite")) {
8058 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01008059 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008060 else if (!strcmp(args[cur_arg], "indirect")) {
8061 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01008062 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008063 else if (!strcmp(args[cur_arg], "insert")) {
8064 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01008065 }
willy tarreau240afa62005-12-17 13:14:35 +01008066 else if (!strcmp(args[cur_arg], "nocache")) {
8067 curproxy->options |= PR_O_COOK_NOC;
8068 }
willy tarreaucd878942005-12-17 13:27:43 +01008069 else if (!strcmp(args[cur_arg], "postonly")) {
8070 curproxy->options |= PR_O_COOK_POST;
8071 }
willy tarreau0174f312005-12-18 01:02:42 +01008072 else if (!strcmp(args[cur_arg], "prefix")) {
8073 curproxy->options |= PR_O_COOK_PFX;
8074 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008075 else {
willy tarreau0174f312005-12-18 01:02:42 +01008076 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008077 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01008078 return -1;
8079 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008080 cur_arg++;
8081 }
willy tarreau0174f312005-12-18 01:02:42 +01008082 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
8083 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
8084 file, linenum);
8085 return -1;
8086 }
8087
8088 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
8089 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01008090 file, linenum);
8091 return -1;
8092 }
willy tarreau12350152005-12-18 01:03:27 +01008093 }/* end else if (!strcmp(args[0], "cookie")) */
8094 else if (!strcmp(args[0], "appsession")) { /* cookie name */
8095// if (curproxy == &defproxy) {
8096// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8097// return -1;
8098// }
8099
8100 if (curproxy->appsession_name != NULL) {
8101// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
8102// file, linenum);
8103// return 0;
8104 free(curproxy->appsession_name);
8105 }
8106
8107 if (*(args[5]) == 0) {
8108 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
8109 file, linenum, args[0]);
8110 return -1;
8111 }
8112 have_appsession = 1;
8113 curproxy->appsession_name = strdup(args[1]);
8114 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
8115 curproxy->appsession_len = atoi(args[3]);
8116 curproxy->appsession_timeout = atoi(args[5]);
8117 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
8118 if (rc) {
8119 Alert("Error Init Appsession Hashtable.\n");
8120 return -1;
8121 }
8122 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01008123 else if (!strcmp(args[0], "capture")) {
8124 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
8125 // if (curproxy == &defproxy) {
8126 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8127 // return -1;
8128 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01008129
willy tarreau4302f492005-12-18 01:00:37 +01008130 if (curproxy->capture_name != NULL) {
8131 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
8132 // file, linenum, args[0]);
8133 // return 0;
8134 free(curproxy->capture_name);
8135 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008136
willy tarreau4302f492005-12-18 01:00:37 +01008137 if (*(args[4]) == 0) {
8138 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
8139 file, linenum, args[0]);
8140 return -1;
8141 }
8142 curproxy->capture_name = strdup(args[2]);
8143 curproxy->capture_namelen = strlen(curproxy->capture_name);
8144 curproxy->capture_len = atol(args[4]);
8145 if (curproxy->capture_len >= CAPTURE_LEN) {
8146 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
8147 file, linenum, CAPTURE_LEN - 1);
8148 curproxy->capture_len = CAPTURE_LEN - 1;
8149 }
8150 curproxy->to_log |= LW_COOKIE;
8151 }
8152 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
8153 struct cap_hdr *hdr;
8154
8155 if (curproxy == &defproxy) {
8156 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
8157 return -1;
8158 }
8159
8160 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
8161 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
8162 file, linenum, args[0], args[1]);
8163 return -1;
8164 }
8165
8166 hdr = calloc(sizeof(struct cap_hdr), 1);
8167 hdr->next = curproxy->req_cap;
8168 hdr->name = strdup(args[3]);
8169 hdr->namelen = strlen(args[3]);
8170 hdr->len = atol(args[5]);
8171 hdr->index = curproxy->nb_req_cap++;
8172 curproxy->req_cap = hdr;
8173 curproxy->to_log |= LW_REQHDR;
8174 }
8175 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
8176 struct cap_hdr *hdr;
8177
8178 if (curproxy == &defproxy) {
8179 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
8180 return -1;
8181 }
8182
8183 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
8184 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
8185 file, linenum, args[0], args[1]);
8186 return -1;
8187 }
8188 hdr = calloc(sizeof(struct cap_hdr), 1);
8189 hdr->next = curproxy->rsp_cap;
8190 hdr->name = strdup(args[3]);
8191 hdr->namelen = strlen(args[3]);
8192 hdr->len = atol(args[5]);
8193 hdr->index = curproxy->nb_rsp_cap++;
8194 curproxy->rsp_cap = hdr;
8195 curproxy->to_log |= LW_RSPHDR;
8196 }
8197 else {
8198 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008199 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008200 return -1;
8201 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008202 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008203 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008204 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008205 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008206 return 0;
8207 }
8208 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008209 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8210 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008211 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008212 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008213 curproxy->contimeout = atol(args[1]);
8214 }
8215 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008216 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008217 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
8218 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008219 return 0;
8220 }
8221 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008222 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8223 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008224 return -1;
8225 }
8226 curproxy->clitimeout = atol(args[1]);
8227 }
8228 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008229 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008230 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008231 return 0;
8232 }
8233 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008234 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8235 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01008236 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008237 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008238 curproxy->srvtimeout = atol(args[1]);
8239 }
8240 else if (!strcmp(args[0], "retries")) { /* connection retries */
8241 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008242 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
8243 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008244 return -1;
8245 }
8246 curproxy->conn_retries = atol(args[1]);
8247 }
willy tarreau9e138862006-05-14 23:06:28 +02008248 else if (!strcmp(args[0], "stats")) {
willy tarreau1f431b52006-05-21 14:46:15 +02008249 if (curproxy != &defproxy && curproxy->uri_auth == defproxy.uri_auth)
8250 curproxy->uri_auth = NULL; /* we must detach from the default config */
8251
willy tarreau9e138862006-05-14 23:06:28 +02008252 if (*(args[1]) == 0) {
willy tarreau1f431b52006-05-21 14:46:15 +02008253 Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'auth', 'scope' or 'enable'.\n", file, linenum, args[0]);
willy tarreau9e138862006-05-14 23:06:28 +02008254 return -1;
8255 } else if (!strcmp(args[1], "uri")) {
8256 if (*(args[2]) == 0) {
8257 Alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
8258 return -1;
8259 } else if (!stats_set_uri(&curproxy->uri_auth, args[2])) {
8260 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8261 return -1;
8262 }
8263 } else if (!strcmp(args[1], "realm")) {
8264 if (*(args[2]) == 0) {
8265 Alert("parsing [%s:%d] : 'realm' needs an realm name.\n", file, linenum);
8266 return -1;
8267 } else if (!stats_set_realm(&curproxy->uri_auth, args[2])) {
8268 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8269 return -1;
8270 }
8271 } else if (!strcmp(args[1], "auth")) {
8272 if (*(args[2]) == 0) {
8273 Alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
8274 return -1;
8275 } else if (!stats_add_auth(&curproxy->uri_auth, args[2])) {
8276 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8277 return -1;
8278 }
willy tarreau1f431b52006-05-21 14:46:15 +02008279 } else if (!strcmp(args[1], "scope")) {
8280 if (*(args[2]) == 0) {
8281 Alert("parsing [%s:%d] : 'scope' needs a proxy name.\n", file, linenum);
8282 return -1;
8283 } else if (!stats_add_scope(&curproxy->uri_auth, args[2])) {
8284 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8285 return -1;
8286 }
willy tarreau9e138862006-05-14 23:06:28 +02008287 } else if (!strcmp(args[1], "enable")) {
8288 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
8289 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8290 return -1;
8291 }
8292 } else {
8293 Alert("parsing [%s:%d] : unknown stats parameter '%s' (expects 'uri', 'realm', 'auth' or 'enable').\n",
8294 file, linenum, args[0]);
8295 return -1;
8296 }
8297 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008298 else if (!strcmp(args[0], "option")) {
8299 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008300 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008301 return -1;
8302 }
8303 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01008304 /* enable reconnections to dispatch */
8305 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01008306#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01008307 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01008308 /* enable transparent proxy connections */
8309 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01008310#endif
8311 else if (!strcmp(args[1], "keepalive"))
8312 /* enable keep-alive */
8313 curproxy->options |= PR_O_KEEPALIVE;
8314 else if (!strcmp(args[1], "forwardfor"))
8315 /* insert x-forwarded-for field */
8316 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01008317 else if (!strcmp(args[1], "logasap"))
8318 /* log as soon as possible, without waiting for the session to complete */
8319 curproxy->options |= PR_O_LOGASAP;
8320 else if (!strcmp(args[1], "httpclose"))
8321 /* force connection: close in both directions in HTTP mode */
8322 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01008323 else if (!strcmp(args[1], "forceclose"))
8324 /* force connection: close in both directions in HTTP mode and enforce end of session */
8325 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01008326 else if (!strcmp(args[1], "checkcache"))
8327 /* require examination of cacheability of the 'set-cookie' field */
8328 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01008329 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01008330 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01008331 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01008332 else if (!strcmp(args[1], "tcplog"))
8333 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01008334 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01008335 else if (!strcmp(args[1], "dontlognull")) {
8336 /* don't log empty requests */
8337 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008338 }
willy tarreaub952e1d2005-12-18 01:31:20 +01008339 else if (!strcmp(args[1], "tcpka")) {
8340 /* enable TCP keep-alives on client and server sessions */
8341 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
8342 }
8343 else if (!strcmp(args[1], "clitcpka")) {
8344 /* enable TCP keep-alives on client sessions */
8345 curproxy->options |= PR_O_TCP_CLI_KA;
8346 }
8347 else if (!strcmp(args[1], "srvtcpka")) {
8348 /* enable TCP keep-alives on server sessions */
8349 curproxy->options |= PR_O_TCP_SRV_KA;
8350 }
Willy TARREAU3481c462006-03-01 22:37:57 +01008351 else if (!strcmp(args[1], "allbackups")) {
8352 /* Use all backup servers simultaneously */
8353 curproxy->options |= PR_O_USE_ALL_BK;
8354 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008355 else if (!strcmp(args[1], "httpchk")) {
8356 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008357 if (curproxy->check_req != NULL) {
8358 free(curproxy->check_req);
8359 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008360 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01008361 if (!*args[2]) { /* no argument */
8362 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
8363 curproxy->check_len = strlen(DEF_CHECK_REQ);
8364 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01008365 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
8366 curproxy->check_req = (char *)malloc(reqlen);
8367 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
8368 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008369 } else { /* more arguments : METHOD URI [HTTP_VER] */
8370 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
8371 if (*args[4])
8372 reqlen += strlen(args[4]);
8373 else
8374 reqlen += strlen("HTTP/1.0");
8375
8376 curproxy->check_req = (char *)malloc(reqlen);
8377 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
8378 "%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 +01008379 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008380 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008381 else if (!strcmp(args[1], "persist")) {
8382 /* persist on using the server specified by the cookie, even when it's down */
8383 curproxy->options |= PR_O_PERSIST;
8384 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008385 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008386 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008387 return -1;
8388 }
8389 return 0;
8390 }
8391 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
8392 /* enable reconnections to dispatch */
8393 curproxy->options |= PR_O_REDISP;
8394 }
willy tarreaua1598082005-12-17 13:08:06 +01008395#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01008396 else if (!strcmp(args[0], "transparent")) {
8397 /* enable transparent proxy connections */
8398 curproxy->options |= PR_O_TRANSP;
8399 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008400#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01008401 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
8402 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008403 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008404 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008405 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008406 curproxy->maxconn = atol(args[1]);
8407 }
8408 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
8409 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008410 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008411 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008412 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008413 curproxy->grace = atol(args[1]);
8414 }
8415 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01008416 if (curproxy == &defproxy) {
8417 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8418 return -1;
8419 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008420 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008421 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008422 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008423 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008424 curproxy->dispatch_addr = *str2sa(args[1]);
8425 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008426 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01008427 if (*(args[1])) {
8428 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008429 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01008430 }
willy tarreau1a3442d2006-03-24 21:03:20 +01008431 else if (!strcmp(args[1], "source")) {
8432 curproxy->options |= PR_O_BALANCE_SH;
8433 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008434 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01008435 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008436 return -1;
8437 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008438 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008439 else /* if no option is set, use round-robin by default */
8440 curproxy->options |= PR_O_BALANCE_RR;
8441 }
8442 else if (!strcmp(args[0], "server")) { /* server address */
8443 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008444 char *rport;
8445 char *raddr;
8446 short realport;
8447 int do_check;
8448
8449 if (curproxy == &defproxy) {
8450 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8451 return -1;
8452 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008453
willy tarreaua41a8b42005-12-17 14:02:24 +01008454 if (!*args[2]) {
8455 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008456 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008457 return -1;
8458 }
8459 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
8460 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8461 return -1;
8462 }
willy tarreau0174f312005-12-18 01:02:42 +01008463
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008464 /* the servers are linked backwards first */
8465 newsrv->next = curproxy->srv;
8466 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01008467 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008468
willy tarreau18a957c2006-04-12 19:26:23 +02008469 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01008470 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01008471 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01008472 newsrv->id = strdup(args[1]);
8473
8474 /* several ways to check the port component :
8475 * - IP => port=+0, relative
8476 * - IP: => port=+0, relative
8477 * - IP:N => port=N, absolute
8478 * - IP:+N => port=+N, relative
8479 * - IP:-N => port=-N, relative
8480 */
8481 raddr = strdup(args[2]);
8482 rport = strchr(raddr, ':');
8483 if (rport) {
8484 *rport++ = 0;
8485 realport = atol(rport);
8486 if (!isdigit((int)*rport))
8487 newsrv->state |= SRV_MAPPORTS;
8488 } else {
8489 realport = 0;
8490 newsrv->state |= SRV_MAPPORTS;
8491 }
8492
8493 newsrv->addr = *str2sa(raddr);
8494 newsrv->addr.sin_port = htons(realport);
8495 free(raddr);
8496
willy tarreau9fe663a2005-12-17 13:02:59 +01008497 newsrv->curfd = -1; /* no health-check in progress */
8498 newsrv->inter = DEF_CHKINTR;
8499 newsrv->rise = DEF_RISETIME;
8500 newsrv->fall = DEF_FALLTIME;
8501 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
8502 cur_arg = 3;
8503 while (*args[cur_arg]) {
8504 if (!strcmp(args[cur_arg], "cookie")) {
8505 newsrv->cookie = strdup(args[cur_arg + 1]);
8506 newsrv->cklen = strlen(args[cur_arg + 1]);
8507 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01008508 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008509 else if (!strcmp(args[cur_arg], "rise")) {
8510 newsrv->rise = atol(args[cur_arg + 1]);
8511 newsrv->health = newsrv->rise;
8512 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01008513 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008514 else if (!strcmp(args[cur_arg], "fall")) {
8515 newsrv->fall = atol(args[cur_arg + 1]);
8516 cur_arg += 2;
8517 }
8518 else if (!strcmp(args[cur_arg], "inter")) {
8519 newsrv->inter = atol(args[cur_arg + 1]);
8520 cur_arg += 2;
8521 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008522 else if (!strcmp(args[cur_arg], "port")) {
8523 newsrv->check_port = atol(args[cur_arg + 1]);
8524 cur_arg += 2;
8525 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008526 else if (!strcmp(args[cur_arg], "backup")) {
8527 newsrv->state |= SRV_BACKUP;
8528 cur_arg ++;
8529 }
willy tarreaue3f023f2006-04-08 21:52:24 +02008530 else if (!strcmp(args[cur_arg], "weight")) {
8531 int w;
8532 w = atol(args[cur_arg + 1]);
8533 if (w < 1 || w > 256) {
8534 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
8535 file, linenum, newsrv->id, w);
8536 return -1;
8537 }
8538 newsrv->uweight = w - 1;
8539 cur_arg += 2;
8540 }
willy tarreau18a957c2006-04-12 19:26:23 +02008541 else if (!strcmp(args[cur_arg], "maxconn")) {
8542 newsrv->maxconn = atol(args[cur_arg + 1]);
8543 cur_arg += 2;
8544 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008545 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01008546 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01008547 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008548 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008549 }
willy tarreau0174f312005-12-18 01:02:42 +01008550 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
8551 if (!*args[cur_arg + 1]) {
8552 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
8553 file, linenum, "source");
8554 return -1;
8555 }
8556 newsrv->state |= SRV_BIND_SRC;
8557 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
8558 cur_arg += 2;
8559 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008560 else {
willy tarreaue3f023f2006-04-08 21:52:24 +02008561 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 +01008562 file, linenum, newsrv->id);
8563 return -1;
8564 }
8565 }
8566
8567 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008568 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
8569 newsrv->check_port = realport; /* by default */
8570 if (!newsrv->check_port) {
8571 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 +01008572 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01008573 return -1;
8574 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008575 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01008576 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008577
willy tarreau62084d42006-03-24 18:57:41 +01008578 if (newsrv->state & SRV_BACKUP)
8579 curproxy->srv_bck++;
8580 else
8581 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01008582 }
8583 else if (!strcmp(args[0], "log")) { /* syslog server address */
8584 struct sockaddr_in *sa;
8585 int facility;
8586
8587 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
8588 curproxy->logfac1 = global.logfac1;
8589 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01008590 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008591 curproxy->logfac2 = global.logfac2;
8592 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01008593 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01008594 }
8595 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01008596 int level;
8597
willy tarreau0f7af912005-12-17 12:21:26 +01008598 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
8599 if (!strcmp(log_facilities[facility], args[2]))
8600 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01008601
willy tarreau0f7af912005-12-17 12:21:26 +01008602 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008603 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01008604 exit(1);
8605 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008606
willy tarreau8337c6b2005-12-17 13:41:01 +01008607 level = 7; /* max syslog level = debug */
8608 if (*(args[3])) {
8609 while (level >= 0 && strcmp(log_levels[level], args[3]))
8610 level--;
8611 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008612 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008613 exit(1);
8614 }
8615 }
8616
willy tarreau0f7af912005-12-17 12:21:26 +01008617 sa = str2sa(args[1]);
8618 if (!sa->sin_port)
8619 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01008620
willy tarreau0f7af912005-12-17 12:21:26 +01008621 if (curproxy->logfac1 == -1) {
8622 curproxy->logsrv1 = *sa;
8623 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01008624 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01008625 }
8626 else if (curproxy->logfac2 == -1) {
8627 curproxy->logsrv2 = *sa;
8628 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01008629 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01008630 }
8631 else {
8632 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01008633 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008634 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008635 }
8636 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008637 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01008638 file, linenum);
8639 return -1;
8640 }
8641 }
willy tarreaua1598082005-12-17 13:08:06 +01008642 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01008643 if (!*args[1]) {
8644 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008645 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01008646 return -1;
8647 }
8648
8649 curproxy->source_addr = *str2sa(args[1]);
8650 curproxy->options |= PR_O_BIND_SRC;
8651 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008652 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
8653 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008654 if (curproxy == &defproxy) {
8655 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8656 return -1;
8657 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008658
8659 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008660 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8661 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008662 return -1;
8663 }
8664
8665 preg = calloc(1, sizeof(regex_t));
8666 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008667 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008668 return -1;
8669 }
8670
willy tarreauc1f47532005-12-18 01:08:26 +01008671 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8672 if (err) {
8673 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8674 file, linenum, *err);
8675 return -1;
8676 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008677 }
8678 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
8679 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008680 if (curproxy == &defproxy) {
8681 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8682 return -1;
8683 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008684
8685 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008686 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008687 return -1;
8688 }
8689
8690 preg = calloc(1, sizeof(regex_t));
8691 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008692 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008693 return -1;
8694 }
8695
8696 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8697 }
8698 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
8699 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008700 if (curproxy == &defproxy) {
8701 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8702 return -1;
8703 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008704
8705 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008706 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008707 return -1;
8708 }
8709
8710 preg = calloc(1, sizeof(regex_t));
8711 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008712 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008713 return -1;
8714 }
8715
8716 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8717 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008718 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
8719 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008720 if (curproxy == &defproxy) {
8721 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8722 return -1;
8723 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008724
8725 if (*(args[1]) == 0) {
8726 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8727 return -1;
8728 }
8729
8730 preg = calloc(1, sizeof(regex_t));
8731 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8732 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8733 return -1;
8734 }
8735
8736 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8737 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008738 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
8739 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008740 if (curproxy == &defproxy) {
8741 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8742 return -1;
8743 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008744
8745 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008746 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008747 return -1;
8748 }
8749
8750 preg = calloc(1, sizeof(regex_t));
8751 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008752 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008753 return -1;
8754 }
8755
8756 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8757 }
8758 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
8759 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008760 if (curproxy == &defproxy) {
8761 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8762 return -1;
8763 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008764
8765 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008766 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8767 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008768 return -1;
8769 }
8770
8771 preg = calloc(1, sizeof(regex_t));
8772 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008773 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008774 return -1;
8775 }
8776
willy tarreauc1f47532005-12-18 01:08:26 +01008777 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8778 if (err) {
8779 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8780 file, linenum, *err);
8781 return -1;
8782 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008783 }
8784 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
8785 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008786 if (curproxy == &defproxy) {
8787 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8788 return -1;
8789 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008790
8791 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008792 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008793 return -1;
8794 }
8795
8796 preg = calloc(1, sizeof(regex_t));
8797 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008798 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008799 return -1;
8800 }
8801
8802 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8803 }
8804 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
8805 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008806 if (curproxy == &defproxy) {
8807 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8808 return -1;
8809 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008810
8811 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008812 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008813 return -1;
8814 }
8815
8816 preg = calloc(1, sizeof(regex_t));
8817 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008818 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008819 return -1;
8820 }
8821
8822 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8823 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008824 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
8825 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008826 if (curproxy == &defproxy) {
8827 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8828 return -1;
8829 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008830
8831 if (*(args[1]) == 0) {
8832 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8833 return -1;
8834 }
8835
8836 preg = calloc(1, sizeof(regex_t));
8837 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8838 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8839 return -1;
8840 }
8841
8842 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8843 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008844 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
8845 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008846 if (curproxy == &defproxy) {
8847 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8848 return -1;
8849 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008850
8851 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008852 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008853 return -1;
8854 }
8855
8856 preg = calloc(1, sizeof(regex_t));
8857 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008858 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008859 return -1;
8860 }
8861
8862 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8863 }
8864 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008865 if (curproxy == &defproxy) {
8866 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8867 return -1;
8868 }
8869
willy tarreau9fe663a2005-12-17 13:02:59 +01008870 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008871 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008872 return 0;
8873 }
8874
8875 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008876 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008877 return -1;
8878 }
8879
willy tarreau4302f492005-12-18 01:00:37 +01008880 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
8881 }
8882 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
8883 regex_t *preg;
8884
8885 if (*(args[1]) == 0 || *(args[2]) == 0) {
8886 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8887 file, linenum, args[0]);
8888 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008889 }
willy tarreau4302f492005-12-18 01:00:37 +01008890
8891 preg = calloc(1, sizeof(regex_t));
8892 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8893 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8894 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008895 }
willy tarreau4302f492005-12-18 01:00:37 +01008896
willy tarreauc1f47532005-12-18 01:08:26 +01008897 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8898 if (err) {
8899 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8900 file, linenum, *err);
8901 return -1;
8902 }
willy tarreau4302f492005-12-18 01:00:37 +01008903 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008904 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
8905 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008906 if (curproxy == &defproxy) {
8907 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8908 return -1;
8909 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008910
8911 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008912 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008913 return -1;
8914 }
willy tarreaue39cd132005-12-17 13:00:18 +01008915
willy tarreau9fe663a2005-12-17 13:02:59 +01008916 preg = calloc(1, sizeof(regex_t));
8917 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008918 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008919 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008920 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008921
willy tarreauc1f47532005-12-18 01:08:26 +01008922 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8923 if (err) {
8924 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8925 file, linenum, *err);
8926 return -1;
8927 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008928 }
willy tarreau982249e2005-12-18 00:57:06 +01008929 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
8930 regex_t *preg;
8931 if (curproxy == &defproxy) {
8932 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8933 return -1;
8934 }
8935
8936 if (*(args[1]) == 0) {
8937 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8938 return -1;
8939 }
8940
8941 preg = calloc(1, sizeof(regex_t));
8942 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8943 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8944 return -1;
8945 }
8946
willy tarreauc1f47532005-12-18 01:08:26 +01008947 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8948 if (err) {
8949 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8950 file, linenum, *err);
8951 return -1;
8952 }
willy tarreau982249e2005-12-18 00:57:06 +01008953 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008954 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01008955 regex_t *preg;
8956 if (curproxy == &defproxy) {
8957 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8958 return -1;
8959 }
willy tarreaue39cd132005-12-17 13:00:18 +01008960
willy tarreaua41a8b42005-12-17 14:02:24 +01008961 if (*(args[1]) == 0 || *(args[2]) == 0) {
8962 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8963 file, linenum, args[0]);
8964 return -1;
8965 }
willy tarreaue39cd132005-12-17 13:00:18 +01008966
willy tarreaua41a8b42005-12-17 14:02:24 +01008967 preg = calloc(1, sizeof(regex_t));
8968 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8969 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8970 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008971 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008972
willy tarreauc1f47532005-12-18 01:08:26 +01008973 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8974 if (err) {
8975 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8976 file, linenum, *err);
8977 return -1;
8978 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008979 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008980 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
8981 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008982 if (curproxy == &defproxy) {
8983 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8984 return -1;
8985 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008986
8987 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008988 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008989 return -1;
8990 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008991
willy tarreau9fe663a2005-12-17 13:02:59 +01008992 preg = calloc(1, sizeof(regex_t));
8993 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008994 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008995 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008996 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008997
willy tarreauc1f47532005-12-18 01:08:26 +01008998 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8999 if (err) {
9000 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
9001 file, linenum, *err);
9002 return -1;
9003 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009004 }
willy tarreau982249e2005-12-18 00:57:06 +01009005 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
9006 regex_t *preg;
9007 if (curproxy == &defproxy) {
9008 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9009 return -1;
9010 }
9011
9012 if (*(args[1]) == 0) {
9013 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
9014 return -1;
9015 }
9016
9017 preg = calloc(1, sizeof(regex_t));
9018 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
9019 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
9020 return -1;
9021 }
9022
willy tarreauc1f47532005-12-18 01:08:26 +01009023 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
9024 if (err) {
9025 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
9026 file, linenum, *err);
9027 return -1;
9028 }
willy tarreau982249e2005-12-18 00:57:06 +01009029 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009030 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01009031 if (curproxy == &defproxy) {
9032 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9033 return -1;
9034 }
9035
willy tarreau9fe663a2005-12-17 13:02:59 +01009036 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009037 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009038 return 0;
9039 }
9040
9041 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009042 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009043 return -1;
9044 }
9045
9046 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
9047 }
willy tarreauc1f47532005-12-18 01:08:26 +01009048 else if (!strcmp(args[0], "errorloc") ||
9049 !strcmp(args[0], "errorloc302") ||
9050 !strcmp(args[0], "errorloc303")) { /* error location */
9051 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009052 char *err;
9053
willy tarreaueedaa9f2005-12-17 14:08:03 +01009054 // if (curproxy == &defproxy) {
9055 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9056 // return -1;
9057 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01009058
willy tarreau8337c6b2005-12-17 13:41:01 +01009059 if (*(args[2]) == 0) {
9060 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
9061 return -1;
9062 }
9063
9064 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01009065 if (!strcmp(args[0], "errorloc303")) {
9066 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
9067 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
9068 } else {
9069 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
9070 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
9071 }
willy tarreau8337c6b2005-12-17 13:41:01 +01009072
9073 if (errnum == 400) {
9074 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009075 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009076 free(curproxy->errmsg.msg400);
9077 }
9078 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009079 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009080 }
9081 else if (errnum == 403) {
9082 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009083 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009084 free(curproxy->errmsg.msg403);
9085 }
9086 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009087 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009088 }
9089 else if (errnum == 408) {
9090 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009091 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009092 free(curproxy->errmsg.msg408);
9093 }
9094 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009095 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009096 }
9097 else if (errnum == 500) {
9098 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009099 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009100 free(curproxy->errmsg.msg500);
9101 }
9102 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009103 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009104 }
9105 else if (errnum == 502) {
9106 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009107 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009108 free(curproxy->errmsg.msg502);
9109 }
9110 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009111 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009112 }
9113 else if (errnum == 503) {
9114 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009115 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009116 free(curproxy->errmsg.msg503);
9117 }
9118 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009119 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009120 }
9121 else if (errnum == 504) {
9122 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009123 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009124 free(curproxy->errmsg.msg504);
9125 }
9126 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009127 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009128 }
9129 else {
9130 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
9131 free(err);
9132 }
9133 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009134 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01009135 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01009136 return -1;
9137 }
9138 return 0;
9139}
willy tarreaue39cd132005-12-17 13:00:18 +01009140
willy tarreau5cbea6f2005-12-17 12:48:26 +01009141
willy tarreau9fe663a2005-12-17 13:02:59 +01009142/*
9143 * This function reads and parses the configuration file given in the argument.
9144 * returns 0 if OK, -1 if error.
9145 */
9146int readcfgfile(char *file) {
9147 char thisline[256];
9148 char *line;
9149 FILE *f;
9150 int linenum = 0;
9151 char *end;
9152 char *args[MAX_LINE_ARGS];
9153 int arg;
9154 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01009155 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01009156 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01009157
willy tarreau9fe663a2005-12-17 13:02:59 +01009158 struct proxy *curproxy = NULL;
9159 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01009160
willy tarreau9fe663a2005-12-17 13:02:59 +01009161 if ((f=fopen(file,"r")) == NULL)
9162 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01009163
willy tarreaueedaa9f2005-12-17 14:08:03 +01009164 init_default_instance();
9165
willy tarreau9fe663a2005-12-17 13:02:59 +01009166 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
9167 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009168
willy tarreau9fe663a2005-12-17 13:02:59 +01009169 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01009170
willy tarreau9fe663a2005-12-17 13:02:59 +01009171 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01009172 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01009173 line++;
9174
9175 arg = 0;
9176 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01009177
willy tarreau9fe663a2005-12-17 13:02:59 +01009178 while (*line && arg < MAX_LINE_ARGS) {
9179 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
9180 * C equivalent value. Other combinations left unchanged (eg: \1).
9181 */
9182 if (*line == '\\') {
9183 int skip = 0;
9184 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
9185 *line = line[1];
9186 skip = 1;
9187 }
9188 else if (line[1] == 'r') {
9189 *line = '\r';
9190 skip = 1;
9191 }
9192 else if (line[1] == 'n') {
9193 *line = '\n';
9194 skip = 1;
9195 }
9196 else if (line[1] == 't') {
9197 *line = '\t';
9198 skip = 1;
9199 }
willy tarreauc1f47532005-12-18 01:08:26 +01009200 else if (line[1] == 'x') {
9201 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
9202 unsigned char hex1, hex2;
9203 hex1 = toupper(line[2]) - '0';
9204 hex2 = toupper(line[3]) - '0';
9205 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
9206 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
9207 *line = (hex1<<4) + hex2;
9208 skip = 3;
9209 }
9210 else {
9211 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
9212 return -1;
9213 }
9214 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009215 if (skip) {
9216 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
9217 end -= skip;
9218 }
9219 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01009220 }
willy tarreaua1598082005-12-17 13:08:06 +01009221 else if (*line == '#' || *line == '\n' || *line == '\r') {
9222 /* end of string, end of loop */
9223 *line = 0;
9224 break;
9225 }
willy tarreauc29948c2005-12-17 13:10:27 +01009226 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009227 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01009228 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01009229 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01009230 line++;
9231 args[++arg] = line;
9232 }
9233 else {
9234 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01009235 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009236 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009237
willy tarreau9fe663a2005-12-17 13:02:59 +01009238 /* empty line */
9239 if (!**args)
9240 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01009241
willy tarreau9fe663a2005-12-17 13:02:59 +01009242 /* zero out remaining args */
9243 while (++arg < MAX_LINE_ARGS) {
9244 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009245 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009246
willy tarreaua41a8b42005-12-17 14:02:24 +01009247 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01009248 confsect = CFG_LISTEN;
9249 else if (!strcmp(args[0], "global")) /* global config */
9250 confsect = CFG_GLOBAL;
9251 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01009252
willy tarreau9fe663a2005-12-17 13:02:59 +01009253 switch (confsect) {
9254 case CFG_LISTEN:
9255 if (cfg_parse_listen(file, linenum, args) < 0)
9256 return -1;
9257 break;
9258 case CFG_GLOBAL:
9259 if (cfg_parse_global(file, linenum, args) < 0)
9260 return -1;
9261 break;
9262 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01009263 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009264 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01009265 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009266
9267
willy tarreau0f7af912005-12-17 12:21:26 +01009268 }
9269 fclose(f);
9270
9271 /*
9272 * Now, check for the integrity of all that we have collected.
9273 */
9274
Willy TARREAU3759f982006-03-01 22:44:17 +01009275 /* will be needed further to delay some tasks */
9276 tv_now(&now);
9277
willy tarreau0f7af912005-12-17 12:21:26 +01009278 if ((curproxy = proxy) == NULL) {
9279 Alert("parsing %s : no <listen> line. Nothing to do !\n",
9280 file);
9281 return -1;
9282 }
9283
9284 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01009285 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01009286 curproxy = curproxy->next;
9287 continue;
9288 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009289
9290 if (curproxy->listen == NULL) {
9291 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);
9292 cfgerr++;
9293 }
9294 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01009295 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01009296 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01009297 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
9298 file, curproxy->id);
9299 cfgerr++;
9300 }
9301 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
9302 if (curproxy->options & PR_O_TRANSP) {
9303 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
9304 file, curproxy->id);
9305 cfgerr++;
9306 }
willy tarreau38d79062006-05-21 14:47:13 +02009307#ifdef WE_DONT_SUPPORT_SERVERLESS_LISTENERS
willy tarreau5cbea6f2005-12-17 12:48:26 +01009308 else if (curproxy->srv == NULL) {
9309 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
9310 file, curproxy->id);
9311 cfgerr++;
9312 }
willy tarreau38d79062006-05-21 14:47:13 +02009313#endif
willy tarreaua1598082005-12-17 13:08:06 +01009314 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01009315 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
9316 file, curproxy->id);
9317 }
9318 }
9319 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01009320 if (curproxy->cookie_name != NULL) {
9321 Warning("parsing %s : cookie will be ignored for listener %s.\n",
9322 file, curproxy->id);
9323 }
9324 if ((newsrv = curproxy->srv) != NULL) {
9325 Warning("parsing %s : servers will be ignored for listener %s.\n",
9326 file, curproxy->id);
9327 }
willy tarreaue39cd132005-12-17 13:00:18 +01009328 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01009329 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
9330 file, curproxy->id);
9331 }
willy tarreaue39cd132005-12-17 13:00:18 +01009332 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01009333 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
9334 file, curproxy->id);
9335 }
9336 }
9337 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
9338 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
9339 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
9340 file, curproxy->id);
9341 cfgerr++;
9342 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009343 }
willy tarreaue3f023f2006-04-08 21:52:24 +02009344
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009345 /* first, we will invert the servers list order */
9346 newsrv = NULL;
9347 while (curproxy->srv) {
9348 struct server *next;
9349
9350 next = curproxy->srv->next;
9351 curproxy->srv->next = newsrv;
9352 newsrv = curproxy->srv;
9353 if (!next)
9354 break;
9355 curproxy->srv = next;
9356 }
9357
9358 /* now, newsrv == curproxy->srv */
9359 if (newsrv) {
9360 struct server *srv;
9361 int pgcd;
9362 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02009363
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009364 /* We will factor the weights to reduce the table,
9365 * using Euclide's largest common divisor algorithm
9366 */
9367 pgcd = newsrv->uweight + 1;
9368 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
9369 int t, w;
9370
9371 w = srv->uweight + 1;
9372 while (w) {
9373 t = pgcd % w;
9374 pgcd = w;
9375 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02009376 }
willy tarreau0f7af912005-12-17 12:21:26 +01009377 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009378
9379 act = bck = 0;
9380 for (srv = newsrv; srv; srv = srv->next) {
9381 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
9382 if (srv->state & SRV_BACKUP)
9383 bck += srv->eweight + 1;
9384 else
9385 act += srv->eweight + 1;
9386 }
9387
9388 /* this is the largest map we will ever need for this servers list */
9389 if (act < bck)
9390 act = bck;
9391
9392 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
9393 /* recounts servers and their weights */
9394 recount_servers(curproxy);
9395 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01009396 }
willy tarreau25c4ea52005-12-18 00:49:49 +01009397
9398 if (curproxy->options & PR_O_LOGASAP)
9399 curproxy->to_log &= ~LW_BYTES;
9400
willy tarreau8337c6b2005-12-17 13:41:01 +01009401 if (curproxy->errmsg.msg400 == NULL) {
9402 curproxy->errmsg.msg400 = (char *)HTTP_400;
9403 curproxy->errmsg.len400 = strlen(HTTP_400);
9404 }
9405 if (curproxy->errmsg.msg403 == NULL) {
9406 curproxy->errmsg.msg403 = (char *)HTTP_403;
9407 curproxy->errmsg.len403 = strlen(HTTP_403);
9408 }
9409 if (curproxy->errmsg.msg408 == NULL) {
9410 curproxy->errmsg.msg408 = (char *)HTTP_408;
9411 curproxy->errmsg.len408 = strlen(HTTP_408);
9412 }
9413 if (curproxy->errmsg.msg500 == NULL) {
9414 curproxy->errmsg.msg500 = (char *)HTTP_500;
9415 curproxy->errmsg.len500 = strlen(HTTP_500);
9416 }
9417 if (curproxy->errmsg.msg502 == NULL) {
9418 curproxy->errmsg.msg502 = (char *)HTTP_502;
9419 curproxy->errmsg.len502 = strlen(HTTP_502);
9420 }
9421 if (curproxy->errmsg.msg503 == NULL) {
9422 curproxy->errmsg.msg503 = (char *)HTTP_503;
9423 curproxy->errmsg.len503 = strlen(HTTP_503);
9424 }
9425 if (curproxy->errmsg.msg504 == NULL) {
9426 curproxy->errmsg.msg504 = (char *)HTTP_504;
9427 curproxy->errmsg.len504 = strlen(HTTP_504);
9428 }
Willy TARREAU3759f982006-03-01 22:44:17 +01009429
willy tarreau59a6cc22006-05-12 01:29:08 +02009430 /*
9431 * If this server supports a maxconn parameter, it needs a dedicated
9432 * tasks to fill the emptied slots when a connection leaves.
9433 */
9434 newsrv = curproxy->srv;
9435 while (newsrv != NULL) {
9436 if (newsrv->maxconn > 0) {
9437 struct task *t;
9438
9439 if ((t = pool_alloc(task)) == NULL) {
9440 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
9441 return -1;
9442 }
9443
9444 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
9445 t->wq = LIST_HEAD(wait_queue[1]); /* already assigned to the eternity queue */
9446 t->state = TASK_IDLE;
9447 t->process = process_srv_queue;
9448 t->context = newsrv;
9449 newsrv->queue_mgt = t;
9450
9451 /* never run it unless specifically woken up */
9452 tv_eternity(&t->expire);
9453 task_queue(t);
9454 }
9455 newsrv = newsrv->next;
9456 }
9457
Willy TARREAU3759f982006-03-01 22:44:17 +01009458 /* now we'll start this proxy's health checks if any */
9459 /* 1- count the checkers to run simultaneously */
9460 nbchk = 0;
9461 mininter = 0;
9462 newsrv = curproxy->srv;
9463 while (newsrv != NULL) {
9464 if (newsrv->state & SRV_CHECKED) {
9465 if (!mininter || mininter > newsrv->inter)
9466 mininter = newsrv->inter;
9467 nbchk++;
9468 }
9469 newsrv = newsrv->next;
9470 }
9471
9472 /* 2- start them as far as possible from each others while respecting
9473 * their own intervals. For this, we will start them after their own
9474 * interval added to the min interval divided by the number of servers,
9475 * weighted by the server's position in the list.
9476 */
9477 if (nbchk > 0) {
9478 struct task *t;
9479 int srvpos;
9480
9481 newsrv = curproxy->srv;
9482 srvpos = 0;
9483 while (newsrv != NULL) {
9484 /* should this server be checked ? */
9485 if (newsrv->state & SRV_CHECKED) {
9486 if ((t = pool_alloc(task)) == NULL) {
9487 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
9488 return -1;
9489 }
9490
9491 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02009492 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
Willy TARREAU3759f982006-03-01 22:44:17 +01009493 t->state = TASK_IDLE;
9494 t->process = process_chk;
9495 t->context = newsrv;
9496
9497 /* check this every ms */
9498 tv_delayfrom(&t->expire, &now,
9499 newsrv->inter + mininter * srvpos / nbchk);
9500 task_queue(t);
9501 //task_wakeup(&rq, t);
9502 srvpos++;
9503 }
9504 newsrv = newsrv->next;
9505 }
9506 }
9507
willy tarreau0f7af912005-12-17 12:21:26 +01009508 curproxy = curproxy->next;
9509 }
9510 if (cfgerr > 0) {
9511 Alert("Errors found in configuration file, aborting.\n");
9512 return -1;
9513 }
9514 else
9515 return 0;
9516}
9517
9518
9519/*
9520 * This function initializes all the necessary variables. It only returns
9521 * if everything is OK. If something fails, it exits.
9522 */
9523void init(int argc, char **argv) {
9524 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01009525 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01009526 char *old_argv = *argv;
9527 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009528 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009529
9530 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01009531 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01009532 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01009533 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01009534 exit(1);
9535 }
9536
willy tarreau746e26b2006-03-25 11:14:35 +01009537#ifdef HAPROXY_MEMMAX
9538 global.rlimit_memmax = HAPROXY_MEMMAX;
9539#endif
9540
Willy TARREAUa9e75f62006-03-01 22:27:48 +01009541 /* initialize the libc's localtime structures once for all so that we
9542 * won't be missing memory if we want to send alerts under OOM conditions.
9543 */
9544 tv_now(&now);
9545 localtime(&now.tv_sec);
willy tarreaue0331262006-05-15 03:02:46 +02009546 start_date = now;
Willy TARREAUa9e75f62006-03-01 22:27:48 +01009547
willy tarreau4302f492005-12-18 01:00:37 +01009548 /* initialize the log header encoding map : '{|}"#' should be encoded with
9549 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
9550 * URL encoding only requires '"', '#' to be encoded as well as non-
9551 * printable characters above.
9552 */
9553 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
9554 memset(url_encode_map, 0, sizeof(url_encode_map));
9555 for (i = 0; i < 32; i++) {
9556 FD_SET(i, hdr_encode_map);
9557 FD_SET(i, url_encode_map);
9558 }
9559 for (i = 127; i < 256; i++) {
9560 FD_SET(i, hdr_encode_map);
9561 FD_SET(i, url_encode_map);
9562 }
9563
9564 tmp = "\"#{|}";
9565 while (*tmp) {
9566 FD_SET(*tmp, hdr_encode_map);
9567 tmp++;
9568 }
9569
9570 tmp = "\"#";
9571 while (*tmp) {
9572 FD_SET(*tmp, url_encode_map);
9573 tmp++;
9574 }
9575
willy tarreau64a3cc32005-12-18 01:13:11 +01009576 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
9577#if defined(ENABLE_POLL)
9578 cfg_polling_mechanism |= POLL_USE_POLL;
9579#endif
9580#if defined(ENABLE_EPOLL)
9581 cfg_polling_mechanism |= POLL_USE_EPOLL;
9582#endif
9583
willy tarreau0f7af912005-12-17 12:21:26 +01009584 pid = getpid();
9585 progname = *argv;
9586 while ((tmp = strchr(progname, '/')) != NULL)
9587 progname = tmp + 1;
9588
9589 argc--; argv++;
9590 while (argc > 0) {
9591 char *flag;
9592
9593 if (**argv == '-') {
9594 flag = *argv+1;
9595
9596 /* 1 arg */
9597 if (*flag == 'v') {
9598 display_version();
9599 exit(0);
9600 }
willy tarreau1c2ad212005-12-18 01:11:29 +01009601#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009602 else if (*flag == 'd' && flag[1] == 'e')
9603 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009604#endif
9605#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009606 else if (*flag == 'd' && flag[1] == 'p')
9607 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009608#endif
willy tarreau982249e2005-12-18 00:57:06 +01009609 else if (*flag == 'V')
9610 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009611 else if (*flag == 'd' && flag[1] == 'b')
9612 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01009613 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01009614 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01009615 else if (*flag == 'c')
9616 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01009617 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01009618 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009619 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01009620 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01009621 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
9622 /* list of pids to finish ('f') or terminate ('t') */
9623
9624 if (flag[1] == 'f')
9625 oldpids_sig = SIGUSR1; /* finish then exit */
9626 else
9627 oldpids_sig = SIGTERM; /* terminate immediately */
9628 argv++; argc--;
9629
9630 if (argc > 0) {
9631 oldpids = calloc(argc, sizeof(int));
9632 while (argc > 0) {
9633 oldpids[nb_oldpids] = atol(*argv);
9634 if (oldpids[nb_oldpids] <= 0)
9635 usage(old_argv);
9636 argc--; argv++;
9637 nb_oldpids++;
9638 }
9639 }
9640 }
willy tarreau2c513732006-04-15 19:25:16 +02009641#if STATTIME > 0
9642 else if (*flag == 's')
9643 arg_mode |= MODE_STATS;
9644 else if (*flag == 'l')
9645 arg_mode |= MODE_LOG;
9646#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009647 else { /* >=2 args */
9648 argv++; argc--;
9649 if (argc == 0)
9650 usage(old_argv);
9651
9652 switch (*flag) {
9653 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01009654 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01009655 case 'N' : cfg_maxpconn = atol(*argv); break;
9656 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009657 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01009658 default: usage(old_argv);
9659 }
9660 }
9661 }
9662 else
9663 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01009664 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01009665 }
9666
willy tarreaud0fb4652005-12-18 01:32:04 +01009667 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009668 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
9669 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01009670
willy tarreau0f7af912005-12-17 12:21:26 +01009671 if (!cfg_cfgfile)
9672 usage(old_argv);
9673
9674 gethostname(hostname, MAX_HOSTNAME_LEN);
9675
willy tarreau12350152005-12-18 01:03:27 +01009676 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01009677 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01009678 if (readcfgfile(cfg_cfgfile) < 0) {
9679 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
9680 exit(1);
9681 }
willy tarreau12350152005-12-18 01:03:27 +01009682 if (have_appsession)
9683 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01009684
willy tarreau982249e2005-12-18 00:57:06 +01009685 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01009686 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
9687 exit(0);
9688 }
9689
willy tarreau9fe663a2005-12-17 13:02:59 +01009690 if (cfg_maxconn > 0)
9691 global.maxconn = cfg_maxconn;
9692
willy tarreaufe2c5c12005-12-17 14:14:34 +01009693 if (cfg_pidfile) {
9694 if (global.pidfile)
9695 free(global.pidfile);
9696 global.pidfile = strdup(cfg_pidfile);
9697 }
9698
willy tarreau9fe663a2005-12-17 13:02:59 +01009699 if (global.maxconn == 0)
9700 global.maxconn = DEFAULT_MAXCONN;
9701
Willy TARREAU203b0b62006-03-12 18:00:28 +01009702 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01009703
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009704 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009705 /* command line debug mode inhibits configuration mode */
9706 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
9707 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009708 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
9709 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01009710
9711 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
9712 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
9713 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
9714 }
9715
9716 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009717 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
9718 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01009719 global.nbproc = 1;
9720 }
9721
9722 if (global.nbproc < 1)
9723 global.nbproc = 1;
9724
willy tarreau0f7af912005-12-17 12:21:26 +01009725 StaticReadEvent = (fd_set *)calloc(1,
9726 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01009727 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01009728 StaticWriteEvent = (fd_set *)calloc(1,
9729 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01009730 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01009731
9732 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01009733 sizeof(struct fdtab) * (global.maxsock));
9734 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01009735 fdtab[i].state = FD_STCLOSE;
9736 }
9737}
9738
9739/*
willy tarreau41310e72006-03-25 18:17:56 +01009740 * this function starts all the proxies. Its return value is composed from
9741 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
9742 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01009743 */
willy tarreau41310e72006-03-25 18:17:56 +01009744int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01009745 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01009746 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01009747 int err = ERR_NONE;
9748 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01009749
9750 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01009751 if (curproxy->state != PR_STNEW)
9752 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01009753
willy tarreau41310e72006-03-25 18:17:56 +01009754 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01009755 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01009756 if (listener->fd != -1)
9757 continue; /* already initialized */
9758
9759 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
9760 if (verbose)
9761 Alert("cannot create listening socket for proxy %s. Aborting.\n",
9762 curproxy->id);
9763 err |= ERR_RETRYABLE;
9764 pxerr |= 1;
9765 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009766 }
willy tarreau0f7af912005-12-17 12:21:26 +01009767
willy tarreaua41a8b42005-12-17 14:02:24 +01009768 if (fd >= global.maxsock) {
9769 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
9770 curproxy->id);
9771 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009772 err |= ERR_FATAL;
9773 pxerr |= 1;
9774 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009775 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009776
willy tarreaua41a8b42005-12-17 14:02:24 +01009777 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
9778 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
9779 (char *) &one, sizeof(one)) == -1)) {
9780 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
9781 curproxy->id);
9782 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009783 err |= ERR_FATAL;
9784 pxerr |= 1;
9785 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009786 }
willy tarreau0f7af912005-12-17 12:21:26 +01009787
willy tarreaua41a8b42005-12-17 14:02:24 +01009788 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
9789 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
9790 curproxy->id);
9791 }
willy tarreau0f7af912005-12-17 12:21:26 +01009792
willy tarreaufac1a862006-05-21 10:20:28 +02009793#ifdef SO_REUSEPORT
9794 /* OpenBSD supports this. As it's present in old libc versions of Linux,
9795 * it might return an error that we will silently ignore.
9796 */
9797 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one));
9798#endif
willy tarreaua41a8b42005-12-17 14:02:24 +01009799 if (bind(fd,
9800 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01009801 listener->addr.ss_family == AF_INET6 ?
9802 sizeof(struct sockaddr_in6) :
9803 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009804 if (verbose)
9805 Alert("cannot bind socket for proxy %s. Aborting.\n",
9806 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009807 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009808 err |= ERR_RETRYABLE;
9809 pxerr |= 1;
9810 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009811 }
willy tarreau0f7af912005-12-17 12:21:26 +01009812
willy tarreaua41a8b42005-12-17 14:02:24 +01009813 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009814 if (verbose)
9815 Alert("cannot listen to socket for proxy %s. Aborting.\n",
9816 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009817 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009818 err |= ERR_RETRYABLE;
9819 pxerr |= 1;
9820 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009821 }
willy tarreau0f7af912005-12-17 12:21:26 +01009822
willy tarreau41310e72006-03-25 18:17:56 +01009823 /* the socket is ready */
9824 listener->fd = fd;
9825
willy tarreaua41a8b42005-12-17 14:02:24 +01009826 /* the function for the accept() event */
9827 fdtab[fd].read = &event_accept;
9828 fdtab[fd].write = NULL; /* never called */
9829 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01009830 fdtab[fd].state = FD_STLISTEN;
9831 FD_SET(fd, StaticReadEvent);
9832 fd_insert(fd);
9833 listeners++;
9834 }
willy tarreau41310e72006-03-25 18:17:56 +01009835
9836 if (!pxerr) {
9837 curproxy->state = PR_STRUN;
9838 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
9839 }
willy tarreau0f7af912005-12-17 12:21:26 +01009840 }
willy tarreau41310e72006-03-25 18:17:56 +01009841
9842 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01009843}
9844
willy tarreaub952e1d2005-12-18 01:31:20 +01009845int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01009846
9847 appsess *temp1,*temp2;
9848 temp1 = (appsess *)key1;
9849 temp2 = (appsess *)key2;
9850
9851 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
9852 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
9853
9854 return (strcmp(temp1->sessid,temp2->sessid) == 0);
9855}/* end match_str */
9856
willy tarreaub952e1d2005-12-18 01:31:20 +01009857void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01009858 appsess *temp1;
9859
9860 //printf("destroy called\n");
9861 temp1 = (appsess *)data;
9862
9863 if (temp1->sessid)
9864 pool_free_to(apools.sessid, temp1->sessid);
9865
9866 if (temp1->serverid)
9867 pool_free_to(apools.serverid, temp1->serverid);
9868
9869 pool_free(appsess, temp1);
9870} /* end destroy */
9871
9872void appsession_cleanup( void )
9873{
9874 struct proxy *p = proxy;
9875
9876 while(p) {
9877 chtbl_destroy(&(p->htbl_proxy));
9878 p = p->next;
9879 }
9880}/* end appsession_cleanup() */
9881
9882void pool_destroy(void **pool)
9883{
9884 void *temp, *next;
9885 next = pool;
9886 while (next) {
9887 temp = next;
9888 next = *(void **)temp;
9889 free(temp);
9890 }
9891}/* end pool_destroy() */
9892
willy tarreaub952e1d2005-12-18 01:31:20 +01009893void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01009894 struct proxy *p = proxy;
9895 struct cap_hdr *h,*h_next;
9896 struct server *s,*s_next;
9897 struct listener *l,*l_next;
9898
9899 while (p) {
9900 if (p->id)
9901 free(p->id);
9902
9903 if (p->check_req)
9904 free(p->check_req);
9905
9906 if (p->cookie_name)
9907 free(p->cookie_name);
9908
9909 if (p->capture_name)
9910 free(p->capture_name);
9911
9912 /* only strup if the user have set in config.
9913 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01009914 if (p->errmsg.msg400) free(p->errmsg.msg400);
9915 if (p->errmsg.msg403) free(p->errmsg.msg403);
9916 if (p->errmsg.msg408) free(p->errmsg.msg408);
9917 if (p->errmsg.msg500) free(p->errmsg.msg500);
9918 if (p->errmsg.msg502) free(p->errmsg.msg502);
9919 if (p->errmsg.msg503) free(p->errmsg.msg503);
9920 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01009921 */
9922 if (p->appsession_name)
9923 free(p->appsession_name);
9924
9925 h = p->req_cap;
9926 while (h) {
9927 h_next = h->next;
9928 if (h->name)
9929 free(h->name);
9930 pool_destroy(h->pool);
9931 free(h);
9932 h = h_next;
9933 }/* end while(h) */
9934
9935 h = p->rsp_cap;
9936 while (h) {
9937 h_next = h->next;
9938 if (h->name)
9939 free(h->name);
9940
9941 pool_destroy(h->pool);
9942 free(h);
9943 h = h_next;
9944 }/* end while(h) */
9945
9946 s = p->srv;
9947 while (s) {
9948 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01009949 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01009950 free(s->id);
9951
willy tarreaub952e1d2005-12-18 01:31:20 +01009952 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01009953 free(s->cookie);
9954
9955 free(s);
9956 s = s_next;
9957 }/* end while(s) */
9958
9959 l = p->listen;
9960 while (l) {
9961 l_next = l->next;
9962 free(l);
9963 l = l_next;
9964 }/* end while(l) */
9965
9966 pool_destroy((void **) p->req_cap_pool);
9967 pool_destroy((void **) p->rsp_cap_pool);
9968 p = p->next;
9969 }/* end while(p) */
9970
9971 if (global.chroot) free(global.chroot);
9972 if (global.pidfile) free(global.pidfile);
9973
willy tarreau12350152005-12-18 01:03:27 +01009974 if (StaticReadEvent) free(StaticReadEvent);
9975 if (StaticWriteEvent) free(StaticWriteEvent);
9976 if (fdtab) free(fdtab);
9977
9978 pool_destroy(pool_session);
9979 pool_destroy(pool_buffer);
9980 pool_destroy(pool_fdtab);
9981 pool_destroy(pool_requri);
9982 pool_destroy(pool_task);
9983 pool_destroy(pool_capture);
9984 pool_destroy(pool_appsess);
9985
9986 if (have_appsession) {
9987 pool_destroy(apools.serverid);
9988 pool_destroy(apools.sessid);
9989 }
9990} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01009991
willy tarreau41310e72006-03-25 18:17:56 +01009992/* sends the signal <sig> to all pids found in <oldpids> */
9993static void tell_old_pids(int sig) {
9994 int p;
9995 for (p = 0; p < nb_oldpids; p++)
9996 kill(oldpids[p], sig);
9997}
9998
willy tarreau0f7af912005-12-17 12:21:26 +01009999int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +010010000 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +010010001 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +010010002 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +010010003 init(argc, argv);
10004
willy tarreau0f7af912005-12-17 12:21:26 +010010005 signal(SIGQUIT, dump);
10006 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +010010007 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +010010008#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +010010009 signal(SIGINT, sig_int);
10010 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +010010011#endif
willy tarreau0f7af912005-12-17 12:21:26 +010010012
10013 /* on very high loads, a sigpipe sometimes happen just between the
10014 * getsockopt() which tells "it's OK to write", and the following write :-(
10015 */
willy tarreau3242e862005-12-17 12:27:53 +010010016#ifndef MSG_NOSIGNAL
10017 signal(SIGPIPE, SIG_IGN);
10018#endif
willy tarreau0f7af912005-12-17 12:21:26 +010010019
willy tarreau41310e72006-03-25 18:17:56 +010010020 /* We will loop at most 100 times with 10 ms delay each time.
10021 * That's at most 1 second. We only send a signal to old pids
10022 * if we cannot grab at least one port.
10023 */
10024 retry = MAX_START_RETRIES;
10025 err = ERR_NONE;
10026 while (retry >= 0) {
10027 struct timeval w;
10028 err = start_proxies(retry == 0 || nb_oldpids == 0);
10029 if (err != ERR_RETRYABLE)
10030 break;
10031 if (nb_oldpids == 0)
10032 break;
10033
Willy TARREAU007aa462006-05-14 09:55:23 +020010034 /* FIXME-20060514: Solaris and OpenBSD do not support shutdown() on
10035 * listening sockets. So on those platforms, it would be wiser to
10036 * simply send SIGUSR1, which will not be undoable.
10037 */
willy tarreau41310e72006-03-25 18:17:56 +010010038 tell_old_pids(SIGTTOU);
10039 /* give some time to old processes to stop listening */
10040 w.tv_sec = 0;
10041 w.tv_usec = 10*1000;
10042 select(0, NULL, NULL, NULL, &w);
10043 retry--;
10044 }
10045
10046 /* Note: start_proxies() sends an alert when it fails. */
10047 if (err != ERR_NONE) {
10048 if (retry != MAX_START_RETRIES && nb_oldpids)
10049 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +010010050 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +010010051 }
willy tarreaud0fb4652005-12-18 01:32:04 +010010052
10053 if (listeners == 0) {
10054 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +010010055 /* Note: we don't have to send anything to the old pids because we
10056 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +010010057 exit(1);
10058 }
10059
willy tarreaudbd3bef2006-01-20 19:35:18 +010010060 /* prepare pause/play signals */
10061 signal(SIGTTOU, sig_pause);
10062 signal(SIGTTIN, sig_listen);
10063
Willy TARREAUe3283d12006-03-01 22:15:29 +010010064 if (global.mode & MODE_DAEMON) {
10065 global.mode &= ~MODE_VERBOSE;
10066 global.mode |= MODE_QUIET;
10067 }
10068
willy tarreaud0fb4652005-12-18 01:32:04 +010010069 /* MODE_QUIET can inhibit alerts and warnings below this line */
10070
10071 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +010010072 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +010010073 /* detach from the tty */
10074 fclose(stdin); fclose(stdout); fclose(stderr);
10075 close(0); close(1); close(2);
10076 }
willy tarreau0f7af912005-12-17 12:21:26 +010010077
willy tarreaufe2c5c12005-12-17 14:14:34 +010010078 /* open log & pid files before the chroot */
10079 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
10080 int pidfd;
10081 unlink(global.pidfile);
10082 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
10083 if (pidfd < 0) {
10084 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +010010085 if (nb_oldpids)
10086 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +010010087 exit(1);
10088 }
10089 pidfile = fdopen(pidfd, "w");
10090 }
willy tarreau9fe663a2005-12-17 13:02:59 +010010091
10092 /* chroot if needed */
10093 if (global.chroot != NULL) {
10094 if (chroot(global.chroot) == -1) {
10095 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +010010096 if (nb_oldpids)
10097 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +010010098 }
10099 chdir("/");
10100 }
10101
willy tarreaub1285d52005-12-18 01:20:14 +010010102 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +010010103 if (!global.rlimit_nofile)
10104 global.rlimit_nofile = global.maxsock;
10105
willy tarreaub1285d52005-12-18 01:20:14 +010010106 if (global.rlimit_nofile) {
10107 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
10108 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
10109 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
10110 }
willy tarreau746e26b2006-03-25 11:14:35 +010010111 }
10112
10113 if (global.rlimit_memmax) {
10114 limit.rlim_cur = limit.rlim_max =
10115 global.rlimit_memmax * 1048576 / global.nbproc;
10116#ifdef RLIMIT_AS
10117 if (setrlimit(RLIMIT_AS, &limit) == -1) {
10118 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
10119 argv[0], global.rlimit_memmax);
10120 }
10121#else
10122 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
10123 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
10124 argv[0], global.rlimit_memmax);
10125 }
10126#endif
willy tarreaub1285d52005-12-18 01:20:14 +010010127 }
10128
willy tarreau41310e72006-03-25 18:17:56 +010010129 if (nb_oldpids)
10130 tell_old_pids(oldpids_sig);
10131
10132 /* Note that any error at this stage will be fatal because we will not
10133 * be able to restart the old pids.
10134 */
10135
willy tarreau9fe663a2005-12-17 13:02:59 +010010136 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +010010137 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +010010138 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
10139 exit(1);
10140 }
10141
willy tarreau036e1ce2005-12-17 13:46:33 +010010142 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +010010143 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
10144 exit(1);
10145 }
10146
willy tarreaub1285d52005-12-18 01:20:14 +010010147 /* check ulimits */
10148 limit.rlim_cur = limit.rlim_max = 0;
10149 getrlimit(RLIMIT_NOFILE, &limit);
10150 if (limit.rlim_cur < global.maxsock) {
10151 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",
10152 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
10153 }
10154
willy tarreau9fe663a2005-12-17 13:02:59 +010010155 if (global.mode & MODE_DAEMON) {
10156 int ret = 0;
10157 int proc;
10158
10159 /* the father launches the required number of processes */
10160 for (proc = 0; proc < global.nbproc; proc++) {
10161 ret = fork();
10162 if (ret < 0) {
10163 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +010010164 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +010010165 exit(1); /* there has been an error */
10166 }
10167 else if (ret == 0) /* child breaks here */
10168 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +010010169 if (pidfile != NULL) {
10170 fprintf(pidfile, "%d\n", ret);
10171 fflush(pidfile);
10172 }
willy tarreau9fe663a2005-12-17 13:02:59 +010010173 }
willy tarreaufe2c5c12005-12-17 14:14:34 +010010174 /* close the pidfile both in children and father */
10175 if (pidfile != NULL)
10176 fclose(pidfile);
10177 free(global.pidfile);
10178
willy tarreau9fe663a2005-12-17 13:02:59 +010010179 if (proc == global.nbproc)
10180 exit(0); /* parent must leave */
10181
willy tarreau750a4722005-12-17 13:21:24 +010010182 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
10183 * that we can detach from the TTY. We MUST NOT do it in other cases since
10184 * it would have already be done, and 0-2 would have been affected to listening
10185 * sockets
10186 */
10187 if (!(global.mode & MODE_QUIET)) {
10188 /* detach from the tty */
10189 fclose(stdin); fclose(stdout); fclose(stderr);
10190 close(0); close(1); close(2); /* close all fd's */
10191 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
10192 }
willy tarreaua1598082005-12-17 13:08:06 +010010193 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +010010194 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +010010195 }
10196
willy tarreau1c2ad212005-12-18 01:11:29 +010010197#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +010010198 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010199 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
10200 epoll_loop(POLL_LOOP_ACTION_RUN);
10201 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010202 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010203 }
10204 else {
willy tarreau64a3cc32005-12-18 01:13:11 +010010205 Warning("epoll() is not available. Using poll()/select() instead.\n");
10206 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010207 }
10208 }
10209#endif
10210
10211#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +010010212 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010213 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
10214 poll_loop(POLL_LOOP_ACTION_RUN);
10215 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010216 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010217 }
10218 else {
10219 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +010010220 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010221 }
10222 }
10223#endif
willy tarreau64a3cc32005-12-18 01:13:11 +010010224 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010225 if (select_loop(POLL_LOOP_ACTION_INIT)) {
10226 select_loop(POLL_LOOP_ACTION_RUN);
10227 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010228 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +010010229 }
10230 }
10231
willy tarreau0f7af912005-12-17 12:21:26 +010010232
willy tarreau12350152005-12-18 01:03:27 +010010233 /* Free all Hash Keys and all Hash elements */
10234 appsession_cleanup();
10235 /* Do some cleanup */
10236 deinit();
10237
willy tarreau0f7af912005-12-17 12:21:26 +010010238 exit(0);
10239}
willy tarreau12350152005-12-18 01:03:27 +010010240
10241#if defined(DEBUG_HASH)
10242static void print_table(const CHTbl *htbl) {
10243
10244 ListElmt *element;
10245 int i;
10246 appsess *asession;
10247
10248 /*****************************************************************************
10249 * *
10250 * Display the chained hash table. *
10251 * *
10252 *****************************************************************************/
10253
10254 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
10255
10256 for (i = 0; i < TBLSIZ; i++) {
10257 fprintf(stdout, "Bucket[%03d]\n", i);
10258
10259 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
10260 //fprintf(stdout, "%c", *(char *)list_data(element));
10261 asession = (appsess *)list_data(element);
10262 fprintf(stdout, "ELEM :%s:", asession->sessid);
10263 fprintf(stdout, " Server :%s: \n", asession->serverid);
10264 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
10265 }
10266
10267 fprintf(stdout, "\n");
10268 }
10269 return;
10270} /* end print_table */
10271#endif
10272
10273static int appsession_init(void)
10274{
10275 static int initialized = 0;
10276 int idlen;
10277 struct server *s;
10278 struct proxy *p = proxy;
10279
10280 if (!initialized) {
10281 if (!appsession_task_init()) {
10282 apools.sessid = NULL;
10283 apools.serverid = NULL;
10284 apools.ser_waste = 0;
10285 apools.ser_use = 0;
10286 apools.ser_msize = sizeof(void *);
10287 apools.ses_waste = 0;
10288 apools.ses_use = 0;
10289 apools.ses_msize = sizeof(void *);
10290 while (p) {
10291 s = p->srv;
10292 if (apools.ses_msize < p->appsession_len)
10293 apools.ses_msize = p->appsession_len;
10294 while (s) {
10295 idlen = strlen(s->id);
10296 if (apools.ser_msize < idlen)
10297 apools.ser_msize = idlen;
10298 s = s->next;
10299 }
10300 p = p->next;
10301 }
10302 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
10303 apools.ses_msize ++;
10304 }
10305 else {
10306 fprintf(stderr, "appsession_task_init failed\n");
10307 return -1;
10308 }
10309 initialized ++;
10310 }
10311 return 0;
10312}
10313
10314static int appsession_task_init(void)
10315{
10316 static int initialized = 0;
10317 struct task *t;
10318 if (!initialized) {
10319 if ((t = pool_alloc(task)) == NULL)
10320 return -1;
10321 t->next = t->prev = t->rqnext = NULL;
willy tarreau5e698ef2006-05-02 14:51:00 +020010322 t->wq = LIST_HEAD(wait_queue[0]);
willy tarreau12350152005-12-18 01:03:27 +010010323 t->state = TASK_IDLE;
10324 t->context = NULL;
10325 tv_delayfrom(&t->expire, &now, TBLCHKINT);
10326 task_queue(t);
10327 t->process = appsession_refresh;
10328 initialized ++;
10329 }
10330 return 0;
10331}
10332
10333static int appsession_refresh(struct task *t) {
10334 struct proxy *p = proxy;
10335 CHTbl *htbl;
10336 ListElmt *element, *last;
10337 int i;
10338 appsess *asession;
10339 void *data;
10340
10341 while (p) {
10342 if (p->appsession_name != NULL) {
10343 htbl = &p->htbl_proxy;
10344 /* if we ever give up the use of TBLSIZ, we need to change this */
10345 for (i = 0; i < TBLSIZ; i++) {
10346 last = NULL;
10347 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
10348 asession = (appsess *)list_data(element);
10349 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
10350 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
10351 int len;
10352 /*
10353 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
10354 */
10355 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
10356 asession->sessid, asession->serverid?asession->serverid:"(null)");
10357 write(1, trash, len);
10358 }
10359 /* delete the expired element from within the hash table */
10360 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
10361 && (htbl->table[i].destroy != NULL)) {
10362 htbl->table[i].destroy(data);
10363 }
10364 if (last == NULL) {/* patient lost his head, get a new one */
10365 element = list_head(&htbl->table[i]);
10366 if (element == NULL) break; /* no heads left, go to next patient */
10367 }
10368 else
10369 element = last;
10370 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
10371 else
10372 last = element;
10373 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
10374 }
10375 }
10376 p = p->next;
10377 }
10378 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
10379 return TBLCHKINT;
10380} /* end appsession_refresh */
10381
willy tarreau18a957c2006-04-12 19:26:23 +020010382
10383/*
10384 * Local variables:
10385 * c-indent-level: 4
10386 * c-basic-offset: 4
10387 * End:
10388 */