blob: 7b5daf2d44ba30854d8552c1e5f619f5d46b961d [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 tarreau7e6328d2006-05-21 23:26:20 +020094#define HAPROXY_VERSION "1.2.14"
willy tarreaubfad5742006-03-23 14:19:11 +010095#endif
96
97#ifndef HAPROXY_DATE
willy tarreau7e6328d2006-05-21 23:26:20 +020098#define HAPROXY_DATE "2006/05/21"
willy tarreaubfad5742006-03-23 14:19:11 +010099#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100100
101/* this is for libc5 for example */
102#ifndef TCP_NODELAY
103#define TCP_NODELAY 1
104#endif
105
106#ifndef SHUT_RD
107#define SHUT_RD 0
108#endif
109
110#ifndef SHUT_WR
111#define SHUT_WR 1
112#endif
113
willy tarreau0174f312005-12-18 01:02:42 +0100114/*
115 * BUFSIZE defines the size of a read and write buffer. It is the maximum
116 * amount of bytes which can be stored by the proxy for each session. However,
117 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
118 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
119 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
120 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
121 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
122 */
123#ifndef BUFSIZE
124#define BUFSIZE 16384
125#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100126
127// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100128#ifndef MAXREWRITE
129#define MAXREWRITE (BUFSIZE / 2)
130#endif
131
willy tarreau9fe663a2005-12-17 13:02:59 +0100132#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100133#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100134
willy tarreau5cbea6f2005-12-17 12:48:26 +0100135// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100136#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100137
willy tarreaue39cd132005-12-17 13:00:18 +0100138// max # of added headers per request
139#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100140
141// max # of matches per regexp
142#define MAX_MATCH 10
143
willy tarreau0174f312005-12-18 01:02:42 +0100144// cookie delimitor in "prefix" mode. This character is inserted between the
145// persistence cookie and the original value. The '~' is allowed by RFC2965,
146// and should not be too common in server names.
147#ifndef COOKIE_DELIM
148#define COOKIE_DELIM '~'
149#endif
150
willy tarreau0f7af912005-12-17 12:21:26 +0100151#define CONN_RETRIES 3
152
willy tarreau5cbea6f2005-12-17 12:48:26 +0100153#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100154#define DEF_CHKINTR 2000
155#define DEF_FALLTIME 3
156#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100157#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100158
Willy TARREAU13032e72006-03-12 17:31:45 +0100159/* Default connections limit.
160 *
161 * A system limit can be enforced at build time in order to avoid using haproxy
162 * beyond reasonable system limits. For this, just define SYSTEM_MAXCONN to the
163 * absolute limit accepted by the system. If the configuration specifies a
164 * higher value, it will be capped to SYSTEM_MAXCONN and a warning will be
165 * emitted. The only way to override this limit will be to set it via the
166 * command-line '-n' argument.
167 */
168#ifndef SYSTEM_MAXCONN
willy tarreau9fe663a2005-12-17 13:02:59 +0100169#define DEFAULT_MAXCONN 2000
Willy TARREAU13032e72006-03-12 17:31:45 +0100170#else
171#define DEFAULT_MAXCONN SYSTEM_MAXCONN
172#endif
willy tarreau9fe663a2005-12-17 13:02:59 +0100173
willy tarreaue0331262006-05-15 03:02:46 +0200174#ifdef CONFIG_PRODUCT_NAME
175#define PRODUCT_NAME CONFIG_PRODUCT_NAME
176#else
177#define PRODUCT_NAME "HAProxy"
178#endif
179
willy tarreau0f7af912005-12-17 12:21:26 +0100180/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
181#define INTBITS 5
182
183/* show stats this every millisecond, 0 to disable */
184#ifndef STATTIME
185#define STATTIME 2000
186#endif
187
willy tarreau5cbea6f2005-12-17 12:48:26 +0100188/* this reduces the number of calls to select() by choosing appropriate
189 * sheduler precision in milliseconds. It should be near the minimum
190 * time that is needed by select() to collect all events. All timeouts
191 * are rounded up by adding this value prior to pass it to select().
192 */
193#define SCHEDULER_RESOLUTION 9
194
willy tarreaub952e1d2005-12-18 01:31:20 +0100195#define TIME_ETERNITY -1
196/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100197#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
198#define SETNOW(a) (*a=now)
199
willy tarreau9da061b2005-12-17 12:29:56 +0100200/****** string-specific macros and functions ******/
201/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
202#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
203
204/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
205#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
206
willy tarreau0174f312005-12-18 01:02:42 +0100207/* returns 1 only if only zero or one bit is set in X, which means that X is a
208 * power of 2, and 0 otherwise */
209#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100210/*
211 * copies at most <size-1> chars from <src> to <dst>. Last char is always
212 * set to 0, unless <size> is 0. The number of chars copied is returned
213 * (excluding the terminating zero).
214 * This code has been optimized for size and speed : on x86, it's 45 bytes
215 * long, uses only registers, and consumes only 4 cycles per char.
216 */
willy tarreau750a4722005-12-17 13:21:24 +0100217int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100218 char *orig = dst;
219 if (size) {
220 while (--size && (*dst = *src)) {
221 src++; dst++;
222 }
223 *dst = 0;
224 }
225 return dst - orig;
226}
willy tarreau9da061b2005-12-17 12:29:56 +0100227
willy tarreau4302f492005-12-18 01:00:37 +0100228/*
willy tarreaucb406512006-05-18 00:52:35 +0200229 * This function simply returns a statically allocated string containing
230 * the ascii representation for number 'n' in decimal.
231 */
232char *ultoa(unsigned long n) {
233 /* enough to store 2^63=18446744073709551615 */
234 static char itoa_str[21];
235 char *pos;
236
237 pos = itoa_str + sizeof(itoa_str) - 1;
238 *pos-- = '\0';
239
240 do {
241 *pos-- = '0' + n % 10;
242 n /= 10;
243 } while (n && pos >= itoa_str);
244 return pos + 1;
245}
246
247/*
willy tarreau4302f492005-12-18 01:00:37 +0100248 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
249 * dynamically allocated. In the first case, <__pool> is updated to point to
250 * the next element in the list.
251 */
252#define pool_alloc_from(__pool, __len) ({ \
253 void *__p; \
254 if ((__p = (__pool)) == NULL) \
255 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
256 else { \
257 __pool = *(void **)(__pool); \
258 } \
259 __p; \
260})
261
262/*
263 * Puts a memory area back to the corresponding pool.
264 * Items are chained directly through a pointer that
265 * is written in the beginning of the memory area, so
266 * there's no need for any carrier cell. This implies
267 * that each memory area is at least as big as one
268 * pointer.
269 */
270#define pool_free_to(__pool, __ptr) ({ \
271 *(void **)(__ptr) = (void *)(__pool); \
272 __pool = (void *)(__ptr); \
273})
274
275
willy tarreau0f7af912005-12-17 12:21:26 +0100276#define MEM_OPTIM
277#ifdef MEM_OPTIM
278/*
279 * Returns a pointer to type <type> taken from the
280 * pool <pool_type> or dynamically allocated. In the
281 * first case, <pool_type> is updated to point to the
282 * next element in the list.
283 */
284#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100285 void *__p; \
286 if ((__p = pool_##type) == NULL) \
287 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100288 else { \
289 pool_##type = *(void **)pool_##type; \
290 } \
willy tarreau4302f492005-12-18 01:00:37 +0100291 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100292})
293
294/*
295 * Puts a memory area back to the corresponding pool.
296 * Items are chained directly through a pointer that
297 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100298 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100299 * that each memory area is at least as big as one
300 * pointer.
301 */
302#define pool_free(type, ptr) ({ \
303 *(void **)ptr = (void *)pool_##type; \
304 pool_##type = (void *)ptr; \
305})
306
307#else
308#define pool_alloc(type) (calloc(1,sizeof_##type));
309#define pool_free(type, ptr) (free(ptr));
310#endif /* MEM_OPTIM */
311
willy tarreau5cbea6f2005-12-17 12:48:26 +0100312#define sizeof_task sizeof(struct task)
313#define sizeof_session sizeof(struct session)
willy tarreau18a957c2006-04-12 19:26:23 +0200314#define sizeof_pendconn sizeof(struct pendconn)
willy tarreau0f7af912005-12-17 12:21:26 +0100315#define sizeof_buffer sizeof(struct buffer)
316#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100317#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100318#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100319#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100320#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100321
willy tarreau5cbea6f2005-12-17 12:48:26 +0100322/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100323#define FD_STCLOSE 0
324#define FD_STLISTEN 1
325#define FD_STCONN 2
326#define FD_STREADY 3
327#define FD_STERROR 4
328
willy tarreau5cbea6f2005-12-17 12:48:26 +0100329/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100330#define TASK_IDLE 0
331#define TASK_RUNNING 1
332
willy tarreau5cbea6f2005-12-17 12:48:26 +0100333/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100334#define PR_STNEW 0
335#define PR_STIDLE 1
336#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100337#define PR_STSTOPPED 3
338#define PR_STPAUSED 4
willy tarreaufac1a862006-05-21 10:20:28 +0200339#define PR_STERROR 5
willy tarreau0f7af912005-12-17 12:21:26 +0100340
willy tarreau5cbea6f2005-12-17 12:48:26 +0100341/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100342#define PR_MODE_TCP 0
343#define PR_MODE_HTTP 1
344#define PR_MODE_HEALTH 2
345
willy tarreau1c2ad212005-12-18 01:11:29 +0100346/* possible actions for the *poll() loops */
347#define POLL_LOOP_ACTION_INIT 0
348#define POLL_LOOP_ACTION_RUN 1
349#define POLL_LOOP_ACTION_CLEAN 2
350
willy tarreau64a3cc32005-12-18 01:13:11 +0100351/* poll mechanisms available */
352#define POLL_USE_SELECT (1<<0)
353#define POLL_USE_POLL (1<<1)
354#define POLL_USE_EPOLL (1<<2)
355
willy tarreau5cbea6f2005-12-17 12:48:26 +0100356/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100357#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
358#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
359#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
360#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
361#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
362#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
363#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
364#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau0174f312005-12-18 01:02:42 +0100365#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
366#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
367#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
368#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
369#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
370#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
371#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
372#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
373#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
374#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
375#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100376#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
377#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100378#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100379#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau1a3442d2006-03-24 21:03:20 +0100380#define PR_O_BALANCE_SH 0x00400000 /* balance on source IP hash */
381#define PR_O_BALANCE (PR_O_BALANCE_RR | PR_O_BALANCE_SH)
willy tarreau03a92de2006-05-21 18:26:53 +0200382#define PR_O_ABRT_CLOSE 0x00800000 /* immediately abort request when client closes */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100383
willy tarreaua5e8c662006-04-29 10:43:46 +0200384/* various session flags, bits values 0x01 to 0x20 (shift 0) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100385#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
386#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
387#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
388#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
389#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
390#define SN_POST 0x00000020 /* the request was an HTTP POST */
391
willy tarreaua5e8c662006-04-29 10:43:46 +0200392/* session flags dedicated to cookies : bits values 0x40, 0x80 (0-3 shift 6) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100393#define SN_CK_NONE 0x00000000 /* this session had no cookie */
394#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
395#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
396#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
397#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
398#define SN_CK_SHIFT 6 /* bit shift */
399
willy tarreaua5e8c662006-04-29 10:43:46 +0200400/* session termination conditions, bits values 0x100 to 0x700 (0-7 shift 8) */
willy tarreaub1285d52005-12-18 01:20:14 +0100401#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100402#define SN_ERR_CLITO 0x00000100 /* client time-out */
403#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
404#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
405#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
406#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100407#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
408#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100409#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
410#define SN_ERR_SHIFT 8 /* bit shift */
411
willy tarreaua5e8c662006-04-29 10:43:46 +0200412/* session state at termination, bits values 0x1000 to 0x7000 (0-7 shift 12) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100413#define SN_FINST_R 0x00001000 /* session ended during client request */
414#define SN_FINST_C 0x00002000 /* session ended during server connect */
415#define SN_FINST_H 0x00003000 /* session ended during server headers */
416#define SN_FINST_D 0x00004000 /* session ended during data phase */
417#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
willy tarreau078c79a2006-05-13 12:23:58 +0200418#define SN_FINST_Q 0x00006000 /* session ended while waiting in queue for a server slot */
willy tarreau036e1ce2005-12-17 13:46:33 +0100419#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
420#define SN_FINST_SHIFT 12 /* bit shift */
421
willy tarreaua5e8c662006-04-29 10:43:46 +0200422/* cookie information, bits values 0x10000 to 0x80000 (0-8 shift 16) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100423#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
424#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
425#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
426#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
427#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100428#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100429#define SN_SCK_SHIFT 16 /* bit shift */
430
willy tarreaua5e8c662006-04-29 10:43:46 +0200431/* cacheability management, bits values 0x100000 to 0x300000 (0-3 shift 20) */
willy tarreau97f58572005-12-18 00:53:44 +0100432#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
433#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
434#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100435
willy tarreaua5e8c662006-04-29 10:43:46 +0200436/* various other session flags, bits values 0x400000 and above */
437#define SN_MONITOR 0x00400000 /* this session comes from a monitoring system */
willy tarreaudfece232006-05-02 00:19:57 +0200438#define SN_ASSIGNED 0x00800000 /* no need to assign a server to this session */
439#define SN_ADDR_SET 0x01000000 /* this session's server address has been set */
willy tarreaue0331262006-05-15 03:02:46 +0200440#define SN_SELF_GEN 0x02000000 /* the proxy generates data for the client (eg: stats) */
willy tarreaua5e8c662006-04-29 10:43:46 +0200441
willy tarreaue0331262006-05-15 03:02:46 +0200442/* various data sources for the responses */
443#define DATA_SRC_NONE 0
444#define DATA_SRC_STATS 1
willy tarreaua5e8c662006-04-29 10:43:46 +0200445
willy tarreau1f431b52006-05-21 14:46:15 +0200446/* data transmission states for the responses */
447#define DATA_ST_INIT 0
448#define DATA_ST_DATA 1
449
willy tarreau5cbea6f2005-12-17 12:48:26 +0100450/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100451#define CL_STHEADERS 0
452#define CL_STDATA 1
453#define CL_STSHUTR 2
454#define CL_STSHUTW 3
455#define CL_STCLOSE 4
456
willy tarreau5cbea6f2005-12-17 12:48:26 +0100457/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100458#define SV_STIDLE 0
willy tarreau9fea1942006-05-12 19:46:40 +0200459#define SV_STCONN 1
460#define SV_STHEADERS 2
461#define SV_STDATA 3
462#define SV_STSHUTR 4
463#define SV_STSHUTW 5
464#define SV_STCLOSE 6
willy tarreau0f7af912005-12-17 12:21:26 +0100465
466/* result of an I/O event */
467#define RES_SILENT 0 /* didn't happen */
468#define RES_DATA 1 /* data were sent or received */
469#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
470#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
471
willy tarreau9fe663a2005-12-17 13:02:59 +0100472/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100473#define MODE_DEBUG 1
474#define MODE_STATS 2
475#define MODE_LOG 4
476#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100477#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100478#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100479#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100480#define MODE_STARTING 128
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100481#define MODE_FOREGROUND 256
willy tarreau5cbea6f2005-12-17 12:48:26 +0100482
483/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100484#define SRV_RUNNING 1 /* the server is UP */
485#define SRV_BACKUP 2 /* this server is a backup server */
486#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100487#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100488#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100489
willy tarreaudfece232006-05-02 00:19:57 +0200490/* function which act on servers need to return various errors */
491#define SRV_STATUS_OK 0 /* everything is OK. */
492#define SRV_STATUS_INTERNAL 1 /* other unrecoverable errors. */
493#define SRV_STATUS_NOSRV 2 /* no server is available */
494#define SRV_STATUS_FULL 3 /* the/all server(s) are saturated */
495#define SRV_STATUS_QUEUED 4 /* the/all server(s) are saturated but the connection was queued */
496
willy tarreaue39cd132005-12-17 13:00:18 +0100497/* what to do when a header matches a regex */
498#define ACT_ALLOW 0 /* allow the request */
499#define ACT_REPLACE 1 /* replace the matching header */
500#define ACT_REMOVE 2 /* remove the matching header */
501#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100502#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100503
willy tarreau9fe663a2005-12-17 13:02:59 +0100504/* configuration sections */
505#define CFG_NONE 0
506#define CFG_GLOBAL 1
507#define CFG_LISTEN 2
508
willy tarreaua1598082005-12-17 13:08:06 +0100509/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100510#define LW_DATE 1 /* date */
511#define LW_CLIP 2 /* CLient IP */
512#define LW_SVIP 4 /* SerVer IP */
513#define LW_SVID 8 /* server ID */
514#define LW_REQ 16 /* http REQuest */
515#define LW_RESP 32 /* http RESPonse */
516#define LW_PXIP 64 /* proxy IP */
517#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100518#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100519#define LW_COOKIE 512 /* captured cookie */
520#define LW_REQHDR 1024 /* request header(s) */
521#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100522
willy tarreau41310e72006-03-25 18:17:56 +0100523#define ERR_NONE 0 /* no error */
524#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
525#define ERR_FATAL 2 /* fatal error, may be cumulated */
526
willy tarreau0f7af912005-12-17 12:21:26 +0100527/*********************************************************************/
528
529#define LIST_HEAD(a) ((void *)(&(a)))
530
531/*********************************************************************/
532
willy tarreau9e138862006-05-14 23:06:28 +0200533/* describes a chunk of string */
534struct chunk {
535 char *str; /* beginning of the string itself. Might not be 0-terminated */
536 int len; /* size of the string from first to last char. <0 = uninit. */
537};
538
willy tarreau4302f492005-12-18 01:00:37 +0100539struct cap_hdr {
540 struct cap_hdr *next;
541 char *name; /* header name, case insensitive */
542 int namelen; /* length of the header name, to speed-up lookups */
543 int len; /* capture length, not including terminal zero */
544 int index; /* index in the output array */
545 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
546};
547
willy tarreau0f7af912005-12-17 12:21:26 +0100548struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100549 struct hdr_exp *next;
550 regex_t *preg; /* expression to look for */
551 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
552 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100553};
554
555struct buffer {
556 unsigned int l; /* data length */
557 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100558 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100559 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100560 char data[BUFSIZE];
561};
562
willy tarreau18a957c2006-04-12 19:26:23 +0200563struct pendconn {
564 struct list list; /* chaining ... */
565 struct session *sess; /* the session waiting for a connection */
566 struct server *srv; /* the server we are waiting for */
567};
568
willy tarreau0f7af912005-12-17 12:21:26 +0100569struct server {
570 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100571 int state; /* server state (SRV_*) */
572 int cklen; /* the len of the cookie, to speed up checks */
573 char *cookie; /* the id set in the cookie */
574 char *id; /* just for identification */
willy tarreau18a957c2006-04-12 19:26:23 +0200575 struct list pendconns; /* pending connections */
willy tarreaucb406512006-05-18 00:52:35 +0200576 int nbpend, nbpend_max; /* number of pending connections */
willy tarreau59a6cc22006-05-12 01:29:08 +0200577 struct task *queue_mgt; /* the task associated to the queue processing */
willy tarreau0f7af912005-12-17 12:21:26 +0100578 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100579 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100580 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100581 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100582 int rise, fall; /* time in iterations */
583 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100584 int result; /* 0 = connect OK, -1 = connect KO */
585 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreaue3f023f2006-04-08 21:52:24 +0200586 unsigned char uweight, eweight; /* user-specified weight-1, and effective weight-1 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200587 unsigned int wscore; /* weight score, used during srv map computation */
willy tarreaucb406512006-05-18 00:52:35 +0200588 int cur_sess, cur_sess_max; /* number of currently active sessions (including syn_sent) */
willy tarreaua647c702006-04-15 22:45:52 +0200589 unsigned int cum_sess; /* cumulated number of sessions really sent to this server */
willy tarreauf76e6ca2006-05-21 21:09:55 +0200590 unsigned int maxconn, minconn; /* max # of active sessions (0 = unlimited), min# for dynamic limit. */
willy tarreaucb406512006-05-18 00:52:35 +0200591 unsigned failed_checks, down_trans; /* failed checks and up-down transitions */
willy tarreaue3b30652006-05-21 16:23:22 +0200592 unsigned failed_conns, failed_resp; /* failed connect() and responses */
593 unsigned failed_secu; /* blocked responses because of security concerns */
willy tarreau535ae7a2005-12-17 12:58:00 +0100594 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100595};
596
willy tarreau5cbea6f2005-12-17 12:48:26 +0100597/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100598struct task {
599 struct task *next, *prev; /* chaining ... */
600 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100601 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100602 int state; /* task state : IDLE or RUNNING */
603 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100604 int (*process)(struct task *t); /* the function which processes the task */
605 void *context; /* the task's context */
606};
607
608/* WARNING: if new fields are added, they must be initialized in event_accept() */
609struct session {
610 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100611 /* application specific below */
612 struct timeval crexpire; /* expiration date for a client read */
613 struct timeval cwexpire; /* expiration date for a client write */
614 struct timeval srexpire; /* expiration date for a server read */
615 struct timeval swexpire; /* expiration date for a server write */
616 struct timeval cnexpire; /* expiration date for a connect */
617 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
618 struct proxy *proxy; /* the proxy this socket belongs to */
619 int cli_fd; /* the client side fd */
620 int srv_fd; /* the server side fd */
621 int cli_state; /* state of the client side */
622 int srv_state; /* state of the server side */
623 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100624 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100625 struct buffer *req; /* request buffer */
626 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100627 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100628 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100629 struct server *srv; /* the server being used */
willy tarreau18a957c2006-04-12 19:26:23 +0200630 struct pendconn *pend_pos; /* if not NULL, points to the position in the pending queue */
willy tarreau4302f492005-12-18 01:00:37 +0100631 char **req_cap; /* array of captured request headers (may be NULL) */
632 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreau9e138862006-05-14 23:06:28 +0200633 struct chunk req_line; /* points to first line */
634 struct chunk auth_hdr; /* points to 'Authorization:' header */
willy tarreaua1598082005-12-17 13:08:06 +0100635 struct {
636 int logwait; /* log fields waiting to be collected : LW_* */
637 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
638 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
willy tarreauf32f5242006-05-02 22:54:52 +0200639 long t_queue; /* delay before the session gets out of the connect queue, -1 if never occurs */
willy tarreaua1598082005-12-17 13:08:06 +0100640 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
641 long t_data; /* delay before the first data byte from the server ... */
642 unsigned long t_close; /* total session duration */
willy tarreau5e69b162006-05-12 19:49:37 +0200643 unsigned long srv_queue_size; /* number of sessions waiting for a connect slot on this server at accept() time (in direct assignment) */
644 unsigned long prx_queue_size; /* overall number of sessions waiting for a connect slot on this instance at accept() time */
willy tarreaua1598082005-12-17 13:08:06 +0100645 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100646 char *cli_cookie; /* cookie presented by the client, in capture mode */
647 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100648 int status; /* HTTP status from the server, negative if from proxy */
649 long long bytes; /* number of bytes transferred from the server */
650 } logs;
willy tarreau1f431b52006-05-21 14:46:15 +0200651 short int data_source; /* where to get the data we generate ourselves */
652 short int data_state; /* where to get the data we generate ourselves */
willy tarreaue0331262006-05-15 03:02:46 +0200653 union {
654 struct {
655 struct proxy *px;
656 struct server *sv;
willy tarreau1f431b52006-05-21 14:46:15 +0200657 short px_st, sv_st; /* DATA_ST_INIT or DATA_ST_DATA */
willy tarreaue0331262006-05-15 03:02:46 +0200658 } stats;
659 } data_ctx;
willy tarreau2f6ba652005-12-17 13:57:42 +0100660 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100661};
662
willy tarreaua41a8b42005-12-17 14:02:24 +0100663struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100664 int fd; /* the listen socket */
665 struct sockaddr_storage addr; /* the address we listen to */
666 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100667};
willy tarreauf32f5242006-05-02 22:54:52 +0200668
willy tarreau0f7af912005-12-17 12:21:26 +0100669struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100670 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100671 struct in_addr mon_net, mon_mask; /* don't forward connections from this net (network order) FIXME: should support IPv6 */
willy tarreau0f7af912005-12-17 12:21:26 +0100672 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100673 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200674 struct server *srv; /* known servers */
675 int srv_act, srv_bck; /* # of running servers */
676 int tot_wact, tot_wbck; /* total weights of active and backup servers */
677 struct server **srv_map; /* the server map used to apply weights */
678 int srv_map_sz; /* the size of the effective server map */
679 int srv_rr_idx; /* next server to be elected in round robin mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100680 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100681 int cookie_len; /* strlen(cookie_name), computed only once */
682 char *appsession_name; /* name of the cookie to look for */
683 int appsession_name_len; /* strlen(appsession_name), computed only once */
684 int appsession_len; /* length of the appsession cookie value to be used */
685 int appsession_timeout;
686 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100687 char *capture_name; /* beginning of the name of the cookie to capture */
688 int capture_namelen; /* length of the cookie name to match */
689 int capture_len; /* length of the string to be captured */
willy tarreau9e138862006-05-14 23:06:28 +0200690 struct uri_auth *uri_auth; /* if non-NULL, the (list of) per-URI authentications */
willy tarreau0f7af912005-12-17 12:21:26 +0100691 int clitimeout; /* client I/O timeout (in milliseconds) */
692 int srvtimeout; /* server I/O timeout (in milliseconds) */
693 int contimeout; /* connect timeout (in milliseconds) */
694 char *id; /* proxy id */
willy tarreaudfece232006-05-02 00:19:57 +0200695 struct list pendconns; /* pending connections with no server assigned yet */
willy tarreaucb406512006-05-18 00:52:35 +0200696 int nbpend, nbpend_max; /* number of pending connections with no server assigned yet */
willy tarreauf32f5242006-05-02 22:54:52 +0200697 int totpend; /* total number of pending connections on this instance (for stats) */
willy tarreauf76e6ca2006-05-21 21:09:55 +0200698 unsigned int nbconn, nbconn_max; /* # of active sessions */
willy tarreau14b4d432006-04-07 18:23:29 +0200699 unsigned int cum_conn; /* cumulated number of processed sessions */
willy tarreauf76e6ca2006-05-21 21:09:55 +0200700 unsigned int maxconn; /* max # of active sessions */
willy tarreaue3b30652006-05-21 16:23:22 +0200701 unsigned failed_conns, failed_resp; /* failed connect() and responses */
702 unsigned failed_secu; /* blocked responses because of security concerns */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100703 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100704 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100705 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100706 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100707 struct proxy *next;
708 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100709 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100710 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100711 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100712 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100713 int nb_reqadd, nb_rspadd;
714 struct hdr_exp *req_exp; /* regular expressions for request headers */
715 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100716 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
717 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
718 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
719 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100720 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100721 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100722 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
723 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100724 struct {
725 char *msg400; /* message for error 400 */
726 int len400; /* message length for error 400 */
727 char *msg403; /* message for error 403 */
728 int len403; /* message length for error 403 */
729 char *msg408; /* message for error 408 */
730 int len408; /* message length for error 408 */
731 char *msg500; /* message for error 500 */
732 int len500; /* message length for error 500 */
733 char *msg502; /* message for error 502 */
734 int len502; /* message length for error 502 */
735 char *msg503; /* message for error 503 */
736 int len503; /* message length for error 503 */
737 char *msg504; /* message for error 504 */
738 int len504; /* message length for error 504 */
739 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100740};
741
742/* info about one given fd */
743struct fdtab {
744 int (*read)(int fd); /* read function */
745 int (*write)(int fd); /* write function */
746 struct task *owner; /* the session (or proxy) associated with this fd */
747 int state; /* the state of this fd */
748};
749
750/*********************************************************************/
751
willy tarreaub952e1d2005-12-18 01:31:20 +0100752int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100753int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100754char *cfg_cfgfile = NULL; /* configuration file */
755char *progname = NULL; /* program name */
756int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100757
758/* global options */
759static struct {
760 int uid;
761 int gid;
762 int nbproc;
763 int maxconn;
764 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100765 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100766 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100767 int mode;
768 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100769 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100770 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100771 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100772 struct sockaddr_in logsrv1, logsrv2;
773} global = {
774 logfac1 : -1,
775 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100776 loglev1 : 7, /* max syslog level : debug */
777 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100778 /* others NULL OK */
779};
780
willy tarreau0f7af912005-12-17 12:21:26 +0100781/*********************************************************************/
782
willy tarreau1c2ad212005-12-18 01:11:29 +0100783fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100784 *StaticWriteEvent;
785
willy tarreau64a3cc32005-12-18 01:13:11 +0100786int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100787
willy tarreau0f7af912005-12-17 12:21:26 +0100788void **pool_session = NULL,
willy tarreau18a957c2006-04-12 19:26:23 +0200789 **pool_pendconn = NULL,
willy tarreau0f7af912005-12-17 12:21:26 +0100790 **pool_buffer = NULL,
791 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100792 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100793 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100794 **pool_capture = NULL,
795 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100796
797struct proxy *proxy = NULL; /* list of all existing proxies */
798struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100799struct task *rq = NULL; /* global run queue */
willy tarreau5e698ef2006-05-02 14:51:00 +0200800struct task wait_queue[2] = { /* global wait queue */
801 {
802 prev:LIST_HEAD(wait_queue[0]), /* expirable tasks */
803 next:LIST_HEAD(wait_queue[0]),
804 },
805 {
806 prev:LIST_HEAD(wait_queue[1]), /* non-expirable tasks */
807 next:LIST_HEAD(wait_queue[1]),
808 },
willy tarreau5cbea6f2005-12-17 12:48:26 +0100809};
willy tarreau0f7af912005-12-17 12:21:26 +0100810
willy tarreau0f7af912005-12-17 12:21:26 +0100811static int totalconn = 0; /* total # of terminated sessions */
812static int actconn = 0; /* # of active sessions */
813static int maxfd = 0; /* # of the highest fd + 1 */
814static int listeners = 0; /* # of listeners */
815static int stopping = 0; /* non zero means stopping in progress */
816static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaue0331262006-05-15 03:02:46 +0200817static struct timeval start_date; /* the process's start date */
willy tarreaua41a8b42005-12-17 14:02:24 +0100818static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100819
willy tarreau53e99702006-03-25 18:53:50 +0100820/* Here we store informations about the pids of the processes we may pause
821 * or kill. We will send them a signal every 10 ms until we can bind to all
822 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100823 */
willy tarreau53e99702006-03-25 18:53:50 +0100824#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100825static int nb_oldpids = 0;
826static int *oldpids = NULL;
827static int oldpids_sig; /* use USR1 or TERM */
828
willy tarreau08dedbe2005-12-18 01:13:48 +0100829#if defined(ENABLE_EPOLL)
830/* FIXME: this is dirty, but at the moment, there's no other solution to remove
831 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
832 * structure with pointers to functions such as init_fd() and close_fd(), plus
833 * a private structure with several pointers to places such as below.
834 */
835
836static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
837#endif
838
willy tarreau0f7af912005-12-17 12:21:26 +0100839static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100840/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100841static char trash[BUFSIZE];
842
willy tarreaudd07e972005-12-18 00:48:48 +0100843const int zero = 0;
844const int one = 1;
845
willy tarreau0f7af912005-12-17 12:21:26 +0100846/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100847 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100848 */
849
850#define MAX_SYSLOG_LEN 1024
851#define NB_LOG_FACILITIES 24
852const char *log_facilities[NB_LOG_FACILITIES] = {
853 "kern", "user", "mail", "daemon",
854 "auth", "syslog", "lpr", "news",
855 "uucp", "cron", "auth2", "ftp",
856 "ntp", "audit", "alert", "cron2",
857 "local0", "local1", "local2", "local3",
858 "local4", "local5", "local6", "local7"
859};
860
861
862#define NB_LOG_LEVELS 8
863const char *log_levels[NB_LOG_LEVELS] = {
864 "emerg", "alert", "crit", "err",
865 "warning", "notice", "info", "debug"
866};
867
868#define SYSLOG_PORT 514
869
870const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
871 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100872
willy tarreaub1285d52005-12-18 01:20:14 +0100873const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau078c79a2006-05-13 12:23:58 +0200874const char sess_fin_state[8] = "-RCHDLQ7"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, unknown */
willy tarreau036e1ce2005-12-17 13:46:33 +0100875const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
876const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
877 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
878 unknown, Set-cookie Rewritten */
879
willy tarreau0f7af912005-12-17 12:21:26 +0100880#define MAX_HOSTNAME_LEN 32
881static char hostname[MAX_HOSTNAME_LEN] = "";
882
willy tarreau8337c6b2005-12-17 13:41:01 +0100883const char *HTTP_302 =
884 "HTTP/1.0 302 Found\r\n"
885 "Cache-Control: no-cache\r\n"
886 "Connection: close\r\n"
887 "Location: "; /* not terminated since it will be concatenated with the URL */
888
willy tarreauc1f47532005-12-18 01:08:26 +0100889/* same as 302 except that the browser MUST retry with the GET method */
890const char *HTTP_303 =
891 "HTTP/1.0 303 See Other\r\n"
892 "Cache-Control: no-cache\r\n"
893 "Connection: close\r\n"
894 "Location: "; /* not terminated since it will be concatenated with the URL */
895
willy tarreaua1598082005-12-17 13:08:06 +0100896const char *HTTP_400 =
897 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100898 "Cache-Control: no-cache\r\n"
899 "Connection: close\r\n"
900 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100901 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100902
willy tarreau9e138862006-05-14 23:06:28 +0200903/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
904const char *HTTP_401_fmt =
905 "HTTP/1.0 401 Unauthorized\r\n"
906 "Cache-Control: no-cache\r\n"
907 "Connection: close\r\n"
908 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
909 "\r\n"
910 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
911
willy tarreaua1598082005-12-17 13:08:06 +0100912const char *HTTP_403 =
913 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100914 "Cache-Control: no-cache\r\n"
915 "Connection: close\r\n"
916 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100917 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
918
willy tarreau8337c6b2005-12-17 13:41:01 +0100919const char *HTTP_408 =
920 "HTTP/1.0 408 Request Time-out\r\n"
921 "Cache-Control: no-cache\r\n"
922 "Connection: close\r\n"
923 "\r\n"
924 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
925
willy tarreau750a4722005-12-17 13:21:24 +0100926const char *HTTP_500 =
927 "HTTP/1.0 500 Server Error\r\n"
928 "Cache-Control: no-cache\r\n"
929 "Connection: close\r\n"
930 "\r\n"
931 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100932
933const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100934 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100935 "Cache-Control: no-cache\r\n"
936 "Connection: close\r\n"
937 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100938 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
939
940const char *HTTP_503 =
941 "HTTP/1.0 503 Service Unavailable\r\n"
942 "Cache-Control: no-cache\r\n"
943 "Connection: close\r\n"
944 "\r\n"
945 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
946
947const char *HTTP_504 =
948 "HTTP/1.0 504 Gateway Time-out\r\n"
949 "Cache-Control: no-cache\r\n"
950 "Connection: close\r\n"
951 "\r\n"
952 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100953
willy tarreau0f7af912005-12-17 12:21:26 +0100954/*********************************************************************/
955/* statistics ******************************************************/
956/*********************************************************************/
957
willy tarreau750a4722005-12-17 13:21:24 +0100958#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100959static int stats_tsk_lsrch, stats_tsk_rsrch,
960 stats_tsk_good, stats_tsk_right, stats_tsk_left,
961 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100962#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100963
964
965/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100966/* debugging *******************************************************/
967/*********************************************************************/
968#ifdef DEBUG_FULL
969static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau3504a012006-05-14 23:20:07 +0200970static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau750a4722005-12-17 13:21:24 +0100971#endif
972
973/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100974/* function prototypes *********************************************/
975/*********************************************************************/
976
977int event_accept(int fd);
978int event_cli_read(int fd);
979int event_cli_write(int fd);
980int event_srv_read(int fd);
981int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100982int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100983
willy tarreau12350152005-12-18 01:03:27 +0100984static int appsession_task_init(void);
985static int appsession_init(void);
986static int appsession_refresh(struct task *t);
987
willy tarreau0f7af912005-12-17 12:21:26 +0100988/*********************************************************************/
989/* general purpose functions ***************************************/
990/*********************************************************************/
991
992void display_version() {
993 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100994 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100995}
996
997/*
998 * This function prints the command line usage and exits
999 */
1000void usage(char *name) {
1001 display_version();
1002 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +01001003 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +01001004#if STATTIME > 0
1005 "sl"
1006#endif
willy tarreau746e26b2006-03-25 11:14:35 +01001007 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
1008 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +01001009 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +01001010 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +01001011 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +01001012#if STATTIME > 0
1013 " -s enables statistics output\n"
1014 " -l enables long statistics format\n"
1015#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001016 " -D goes daemon ; implies -q\n"
1017 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +01001018 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +01001019 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +01001020 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +01001021 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +01001022 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001023#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01001024 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001025#endif
1026#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01001027 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001028#endif
willy tarreau53e99702006-03-25 18:53:50 +01001029 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +01001030 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01001031 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +01001032 exit(1);
1033}
1034
1035
1036/*
willy tarreaud0fb4652005-12-18 01:32:04 +01001037 * Displays the message on stderr with the date and pid. Overrides the quiet
1038 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +01001039 */
1040void Alert(char *fmt, ...) {
1041 va_list argp;
1042 struct timeval tv;
1043 struct tm *tm;
1044
willy tarreaud0fb4652005-12-18 01:32:04 +01001045 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001046 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +01001047
willy tarreau5cbea6f2005-12-17 12:48:26 +01001048 gettimeofday(&tv, NULL);
1049 tm=localtime(&tv.tv_sec);
1050 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001051 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001052 vfprintf(stderr, fmt, argp);
1053 fflush(stderr);
1054 va_end(argp);
1055 }
willy tarreau0f7af912005-12-17 12:21:26 +01001056}
1057
1058
1059/*
1060 * Displays the message on stderr with the date and pid.
1061 */
1062void Warning(char *fmt, ...) {
1063 va_list argp;
1064 struct timeval tv;
1065 struct tm *tm;
1066
willy tarreau982249e2005-12-18 00:57:06 +01001067 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001068 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +01001069
willy tarreau5cbea6f2005-12-17 12:48:26 +01001070 gettimeofday(&tv, NULL);
1071 tm=localtime(&tv.tv_sec);
1072 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001073 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001074 vfprintf(stderr, fmt, argp);
1075 fflush(stderr);
1076 va_end(argp);
1077 }
1078}
1079
1080/*
1081 * Displays the message on <out> only if quiet mode is not set.
1082 */
1083void qfprintf(FILE *out, char *fmt, ...) {
1084 va_list argp;
1085
willy tarreau982249e2005-12-18 00:57:06 +01001086 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001087 va_start(argp, fmt);
1088 vfprintf(out, fmt, argp);
1089 fflush(out);
1090 va_end(argp);
1091 }
willy tarreau0f7af912005-12-17 12:21:26 +01001092}
1093
1094
1095/*
1096 * converts <str> to a struct sockaddr_in* which is locally allocated.
1097 * The format is "addr:port", where "addr" can be empty or "*" to indicate
1098 * INADDR_ANY.
1099 */
1100struct sockaddr_in *str2sa(char *str) {
1101 static struct sockaddr_in sa;
1102 char *c;
1103 int port;
1104
willy tarreaua1598082005-12-17 13:08:06 +01001105 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +01001106 str=strdup(str);
1107
1108 if ((c=strrchr(str,':')) != NULL) {
1109 *c++=0;
1110 port=atol(c);
1111 }
1112 else
1113 port=0;
1114
1115 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1116 sa.sin_addr.s_addr = INADDR_ANY;
1117 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01001118 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001119 struct hostent *he;
1120
1121 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001122 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001123 }
1124 else
1125 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1126 }
1127 sa.sin_port=htons(port);
1128 sa.sin_family=AF_INET;
1129
1130 free(str);
1131 return &sa;
1132}
1133
willy tarreaub1285d52005-12-18 01:20:14 +01001134/*
1135 * converts <str> to a two struct in_addr* which are locally allocated.
1136 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1137 * is optionnal and either in the dotted or CIDR notation.
1138 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1139 */
1140int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1141 char *c;
1142 unsigned long len;
1143
1144 memset(mask, 0, sizeof(*mask));
1145 memset(addr, 0, sizeof(*addr));
1146 str=strdup(str);
1147
1148 if ((c = strrchr(str, '/')) != NULL) {
1149 *c++ = 0;
1150 /* c points to the mask */
1151 if (strchr(c, '.') != NULL) { /* dotted notation */
1152 if (!inet_pton(AF_INET, c, mask))
1153 return 0;
1154 }
1155 else { /* mask length */
1156 char *err;
1157 len = strtol(c, &err, 10);
1158 if (!*c || (err && *err) || (unsigned)len > 32)
1159 return 0;
1160 if (len)
1161 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1162 else
1163 mask->s_addr = 0;
1164 }
1165 }
1166 else {
1167 mask->s_addr = 0xFFFFFFFF;
1168 }
1169 if (!inet_pton(AF_INET, str, addr)) {
1170 struct hostent *he;
1171
1172 if ((he = gethostbyname(str)) == NULL) {
1173 return 0;
1174 }
1175 else
1176 *addr = *(struct in_addr *) *(he->h_addr_list);
1177 }
1178 free(str);
1179 return 1;
1180}
1181
willy tarreau9fe663a2005-12-17 13:02:59 +01001182
1183/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001184 * converts <str> to a list of listeners which are dynamically allocated.
1185 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1186 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1187 * - <port> is a numerical port from 1 to 65535 ;
1188 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1189 * This can be repeated as many times as necessary, separated by a coma.
1190 * The <tail> argument is a pointer to a current list which should be appended
1191 * to the tail of the new list. The pointer to the new list is returned.
1192 */
1193struct listener *str2listener(char *str, struct listener *tail) {
1194 struct listener *l;
1195 char *c, *next, *range, *dupstr;
1196 int port, end;
1197
1198 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001199
willy tarreaua41a8b42005-12-17 14:02:24 +01001200 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001201 struct sockaddr_storage ss;
1202
willy tarreaua41a8b42005-12-17 14:02:24 +01001203 str = next;
1204 /* 1) look for the end of the first address */
1205 if ((next = strrchr(str, ',')) != NULL) {
1206 *next++ = 0;
1207 }
1208
willy tarreau8a86dbf2005-12-18 00:45:59 +01001209 /* 2) look for the addr/port delimiter, it's the last colon. */
1210 if ((range = strrchr(str, ':')) == NULL) {
1211 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001212 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001213 }
1214
1215 *range++ = 0;
1216
1217 if (strrchr(str, ':') != NULL) {
1218 /* IPv6 address contains ':' */
1219 memset(&ss, 0, sizeof(ss));
1220 ss.ss_family = AF_INET6;
1221
1222 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1223 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001224 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001225 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001226 }
1227 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001228 memset(&ss, 0, sizeof(ss));
1229 ss.ss_family = AF_INET;
1230
1231 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1232 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1233 }
1234 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1235 struct hostent *he;
1236
1237 if ((he = gethostbyname(str)) == NULL) {
1238 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001239 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001240 }
1241 else
1242 ((struct sockaddr_in *)&ss)->sin_addr =
1243 *(struct in_addr *) *(he->h_addr_list);
1244 }
1245 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001246
1247 /* 3) look for the port-end delimiter */
1248 if ((c = strchr(range, '-')) != NULL) {
1249 *c++ = 0;
1250 end = atol(c);
1251 }
1252 else {
1253 end = atol(range);
1254 }
1255
willy tarreaud0fb4652005-12-18 01:32:04 +01001256 port = atol(range);
1257
1258 if (port < 1 || port > 65535) {
1259 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1260 goto fail;
1261 }
1262
1263 if (end < 1 || end > 65535) {
1264 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1265 goto fail;
1266 }
1267
1268 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001269 l = (struct listener *)calloc(1, sizeof(struct listener));
1270 l->next = tail;
1271 tail = l;
1272
willy tarreau41310e72006-03-25 18:17:56 +01001273 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001274 l->addr = ss;
1275 if (ss.ss_family == AF_INET6)
1276 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1277 else
1278 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1279
willy tarreaua41a8b42005-12-17 14:02:24 +01001280 } /* end for(port) */
1281 } /* end while(next) */
1282 free(dupstr);
1283 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001284 fail:
1285 free(dupstr);
1286 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001287}
1288
willy tarreau4302f492005-12-18 01:00:37 +01001289
1290#define FD_SETS_ARE_BITFIELDS
1291#ifdef FD_SETS_ARE_BITFIELDS
1292/*
1293 * This map is used with all the FD_* macros to check whether a particular bit
1294 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1295 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1296 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1297 * exclusively to the macros.
1298 */
1299fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1300fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1301
1302#else
1303#error "Check if your OS uses bitfields for fd_sets"
1304#endif
1305
1306/* will try to encode the string <string> replacing all characters tagged in
1307 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1308 * prefixed by <escape>, and will store the result between <start> (included
1309 *) and <stop> (excluded), and will always terminate the string with a '\0'
1310 * before <stop>. The position of the '\0' is returned if the conversion
1311 * completes. If bytes are missing between <start> and <stop>, then the
1312 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1313 * cannot even be stored so we return <start> without writing the 0.
1314 * The input string must also be zero-terminated.
1315 */
1316char hextab[16] = "0123456789ABCDEF";
1317char *encode_string(char *start, char *stop,
1318 const char escape, const fd_set *map,
1319 const char *string)
1320{
1321 if (start < stop) {
1322 stop--; /* reserve one byte for the final '\0' */
1323 while (start < stop && *string != 0) {
1324 if (!FD_ISSET((unsigned char)(*string), map))
1325 *start++ = *string;
1326 else {
1327 if (start + 3 >= stop)
1328 break;
1329 *start++ = escape;
1330 *start++ = hextab[(*string >> 4) & 15];
1331 *start++ = hextab[*string & 15];
1332 }
1333 string++;
1334 }
1335 *start = '\0';
1336 }
1337 return start;
1338}
willy tarreaua41a8b42005-12-17 14:02:24 +01001339
1340/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001341 * This function sends a syslog message to both log servers of a proxy,
1342 * or to global log servers if the proxy is NULL.
1343 * It also tries not to waste too much time computing the message header.
1344 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001345 */
1346void send_log(struct proxy *p, int level, char *message, ...) {
1347 static int logfd = -1; /* syslog UDP socket */
1348 static long tvsec = -1; /* to force the string to be initialized */
1349 struct timeval tv;
1350 va_list argp;
1351 static char logmsg[MAX_SYSLOG_LEN];
1352 static char *dataptr = NULL;
1353 int fac_level;
1354 int hdr_len, data_len;
1355 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001356 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001357 int nbloggers = 0;
1358 char *log_ptr;
1359
1360 if (logfd < 0) {
1361 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1362 return;
1363 }
1364
1365 if (level < 0 || progname == NULL || message == NULL)
1366 return;
1367
1368 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001369 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001370 /* this string is rebuild only once a second */
1371 struct tm *tm = localtime(&tv.tv_sec);
1372 tvsec = tv.tv_sec;
1373
willy tarreauc29948c2005-12-17 13:10:27 +01001374 hdr_len = snprintf(logmsg, sizeof(logmsg),
1375 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1376 monthname[tm->tm_mon],
1377 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1378 progname, pid);
1379 /* WARNING: depending upon implementations, snprintf may return
1380 * either -1 or the number of bytes that would be needed to store
1381 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001382 */
willy tarreauc29948c2005-12-17 13:10:27 +01001383 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1384 hdr_len = sizeof(logmsg);
1385
1386 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001387 }
1388
1389 va_start(argp, message);
1390 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001391 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1392 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001393 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001394 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001395
1396 if (p == NULL) {
1397 if (global.logfac1 >= 0) {
1398 sa[nbloggers] = &global.logsrv1;
1399 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001400 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001401 nbloggers++;
1402 }
1403 if (global.logfac2 >= 0) {
1404 sa[nbloggers] = &global.logsrv2;
1405 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001406 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001407 nbloggers++;
1408 }
1409 } else {
1410 if (p->logfac1 >= 0) {
1411 sa[nbloggers] = &p->logsrv1;
1412 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001413 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001414 nbloggers++;
1415 }
1416 if (p->logfac2 >= 0) {
1417 sa[nbloggers] = &p->logsrv2;
1418 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001419 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001420 nbloggers++;
1421 }
1422 }
1423
1424 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001425 /* we can filter the level of the messages that are sent to each logger */
1426 if (level > loglevel[nbloggers])
1427 continue;
1428
willy tarreauc29948c2005-12-17 13:10:27 +01001429 /* For each target, we may have a different facility.
1430 * We can also have a different log level for each message.
1431 * This induces variations in the message header length.
1432 * Since we don't want to recompute it each time, nor copy it every
1433 * time, we only change the facility in the pre-computed header,
1434 * and we change the pointer to the header accordingly.
1435 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001436 fac_level = (facilities[nbloggers] << 3) + level;
1437 log_ptr = logmsg + 3; /* last digit of the log level */
1438 do {
1439 *log_ptr = '0' + fac_level % 10;
1440 fac_level /= 10;
1441 log_ptr--;
1442 } while (fac_level && log_ptr > logmsg);
1443 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001444
willy tarreauc29948c2005-12-17 13:10:27 +01001445 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001446
1447#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001448 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001449 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1450#else
willy tarreauc29948c2005-12-17 13:10:27 +01001451 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001452 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1453#endif
1454 }
willy tarreau0f7af912005-12-17 12:21:26 +01001455}
1456
1457
1458/* sets <tv> to the current time */
1459static inline struct timeval *tv_now(struct timeval *tv) {
1460 if (tv)
1461 gettimeofday(tv, NULL);
1462 return tv;
1463}
1464
1465/*
1466 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1467 */
willy tarreaudab722b2006-05-04 19:23:38 +02001468static struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
willy tarreau0f7af912005-12-17 12:21:26 +01001469 if (!tv || !from)
1470 return NULL;
1471 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1472 tv->tv_sec = from->tv_sec + (ms/1000);
1473 while (tv->tv_usec >= 1000000) {
1474 tv->tv_usec -= 1000000;
1475 tv->tv_sec++;
1476 }
1477 return tv;
1478}
1479
1480/*
1481 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001482 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001483 */
1484static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001485 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001486 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001487 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001488 return 1;
1489 else if (tv1->tv_usec < tv2->tv_usec)
1490 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001491 else if (tv1->tv_usec > tv2->tv_usec)
1492 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001493 else
1494 return 0;
1495}
1496
1497/*
1498 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001499 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001500 */
1501unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1502 int cmp;
1503 unsigned long ret;
1504
1505
willy tarreauef900ab2005-12-17 12:52:52 +01001506 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001507 if (!cmp)
1508 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001509 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001510 struct timeval *tmp = tv1;
1511 tv1 = tv2;
1512 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001513 }
willy tarreauef900ab2005-12-17 12:52:52 +01001514 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001515 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001516 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001517 else
willy tarreauef900ab2005-12-17 12:52:52 +01001518 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001519 return (unsigned long) ret;
1520}
1521
1522/*
willy tarreau750a4722005-12-17 13:21:24 +01001523 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001524 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001525 */
1526static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1527 unsigned long ret;
1528
willy tarreau6e682ce2005-12-17 13:26:49 +01001529 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1530 if (tv2->tv_usec > tv1->tv_usec)
1531 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001532 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001533 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001534 return (unsigned long) ret;
1535}
1536
1537/*
willy tarreau0f7af912005-12-17 12:21:26 +01001538 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001539 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001540 */
willy tarreaudab722b2006-05-04 19:23:38 +02001541static int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001542 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001543 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001544 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001545 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001546 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001547 else
1548 return 0;
1549 }
willy tarreau0f7af912005-12-17 12:21:26 +01001550 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001551 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001552 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001553 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001554 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001555 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001556 else
1557 return 0;
1558}
1559
1560/*
1561 * returns the remaining time between tv1=now and event=tv2
1562 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001563 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001564 */
1565static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1566 unsigned long ret;
1567
willy tarreau0f7af912005-12-17 12:21:26 +01001568 if (tv_cmp_ms(tv1, tv2) >= 0)
1569 return 0; /* event elapsed */
1570
willy tarreauef900ab2005-12-17 12:52:52 +01001571 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001572 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001573 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001574 else
willy tarreauef900ab2005-12-17 12:52:52 +01001575 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001576 return (unsigned long) ret;
1577}
1578
1579
1580/*
1581 * zeroes a struct timeval
1582 */
1583
1584static inline struct timeval *tv_eternity(struct timeval *tv) {
1585 tv->tv_sec = tv->tv_usec = 0;
1586 return tv;
1587}
1588
1589/*
1590 * returns 1 if tv is null, else 0
1591 */
1592static inline int tv_iseternity(struct timeval *tv) {
1593 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1594 return 1;
1595 else
1596 return 0;
1597}
1598
1599/*
1600 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1601 * considering that 0 is the eternity.
1602 */
willy tarreaudab722b2006-05-04 19:23:38 +02001603static int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001604 if (tv_iseternity(tv1))
1605 if (tv_iseternity(tv2))
1606 return 0; /* same */
1607 else
1608 return 1; /* tv1 later than tv2 */
1609 else if (tv_iseternity(tv2))
1610 return -1; /* tv2 later than tv1 */
1611
1612 if (tv1->tv_sec > tv2->tv_sec)
1613 return 1;
1614 else if (tv1->tv_sec < tv2->tv_sec)
1615 return -1;
1616 else if (tv1->tv_usec > tv2->tv_usec)
1617 return 1;
1618 else if (tv1->tv_usec < tv2->tv_usec)
1619 return -1;
1620 else
1621 return 0;
1622}
1623
1624/*
1625 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1626 * considering that 0 is the eternity.
1627 */
willy tarreaudab722b2006-05-04 19:23:38 +02001628static int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001629 if (tv_iseternity(tv1))
1630 if (tv_iseternity(tv2))
1631 return 0; /* same */
1632 else
1633 return 1; /* tv1 later than tv2 */
1634 else if (tv_iseternity(tv2))
1635 return -1; /* tv2 later than tv1 */
1636
willy tarreauefae1842005-12-17 12:51:03 +01001637 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001638 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001639 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001640 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001641 return -1;
1642 else
1643 return 0;
1644 }
1645 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001646 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001647 return 1;
1648 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001649 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001650 return -1;
1651 else
1652 return 0;
1653}
1654
1655/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001656 * returns the remaining time between tv1=now and event=tv2
1657 * if tv2 is passed, 0 is returned.
1658 * Returns TIME_ETERNITY if tv2 is eternity.
1659 */
willy tarreaudab722b2006-05-04 19:23:38 +02001660static unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001661 unsigned long ret;
1662
1663 if (tv_iseternity(tv2))
1664 return TIME_ETERNITY;
1665
1666 if (tv_cmp_ms(tv1, tv2) >= 0)
1667 return 0; /* event elapsed */
1668
1669 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1670 if (tv2->tv_usec > tv1->tv_usec)
1671 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1672 else
1673 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1674 return (unsigned long) ret;
1675}
1676
1677/*
willy tarreau0f7af912005-12-17 12:21:26 +01001678 * returns the first event between tv1 and tv2 into tvmin.
1679 * a zero tv is ignored. tvmin is returned.
1680 */
1681static inline struct timeval *tv_min(struct timeval *tvmin,
1682 struct timeval *tv1, struct timeval *tv2) {
1683
1684 if (tv_cmp2(tv1, tv2) <= 0)
1685 *tvmin = *tv1;
1686 else
1687 *tvmin = *tv2;
1688
1689 return tvmin;
1690}
1691
1692
1693
1694/***********************************************************/
1695/* fd management ***************************************/
1696/***********************************************************/
1697
1698
1699
willy tarreau5cbea6f2005-12-17 12:48:26 +01001700/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1701 * The file descriptor is also closed.
1702 */
willy tarreaudab722b2006-05-04 19:23:38 +02001703static void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001704 FD_CLR(fd, StaticReadEvent);
1705 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001706#if defined(ENABLE_EPOLL)
1707 if (PrevReadEvent) {
1708 FD_CLR(fd, PrevReadEvent);
1709 FD_CLR(fd, PrevWriteEvent);
1710 }
1711#endif
1712
willy tarreau5cbea6f2005-12-17 12:48:26 +01001713 close(fd);
1714 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001715
1716 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1717 maxfd--;
1718}
1719
1720/* recomputes the maxfd limit from the fd */
1721static inline void fd_insert(int fd) {
1722 if (fd+1 > maxfd)
1723 maxfd = fd+1;
1724}
1725
1726/*************************************************************/
1727/* task management ***************************************/
1728/*************************************************************/
1729
willy tarreau5cbea6f2005-12-17 12:48:26 +01001730/* puts the task <t> in run queue <q>, and returns <t> */
1731static inline struct task *task_wakeup(struct task **q, struct task *t) {
1732 if (t->state == TASK_RUNNING)
1733 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001734 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001735 t->rqnext = *q;
1736 t->state = TASK_RUNNING;
1737 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001738 }
1739}
1740
willy tarreau5cbea6f2005-12-17 12:48:26 +01001741/* removes the task <t> from the queue <q>
1742 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001743 * set the run queue to point to the next one, and return it
1744 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001745static inline struct task *task_sleep(struct task **q, struct task *t) {
1746 if (t->state == TASK_RUNNING) {
1747 *q = t->rqnext;
1748 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001749 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001750 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001751}
1752
1753/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001754 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001755 * from the run queue. A pointer to the task itself is returned.
1756 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001757static inline struct task *task_delete(struct task *t) {
1758 t->prev->next = t->next;
1759 t->next->prev = t->prev;
1760 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001761}
1762
1763/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001764 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001765 */
1766static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001767 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001768}
1769
willy tarreau5cbea6f2005-12-17 12:48:26 +01001770/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001771 * may be only moved or left where it was, depending on its timing requirements.
1772 * <task> is returned.
1773 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001774struct task *task_queue(struct task *task) {
1775 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001776 struct task *start_from;
1777
willy tarreau5e698ef2006-05-02 14:51:00 +02001778 /* This is a very dirty hack to queue non-expirable tasks in another queue
1779 * in order to avoid pulluting the tail of the standard queue. This will go
1780 * away with the new O(log(n)) scheduler anyway.
1781 */
1782 if (tv_iseternity(&task->expire)) {
1783 /* if the task was queued in the standard wait queue, we must dequeue it */
1784 if (task->prev) {
1785 if (task->wq == LIST_HEAD(wait_queue[1]))
1786 return task;
1787 else {
1788 task_delete(task);
1789 task->prev = NULL;
1790 }
1791 }
1792 list = task->wq = LIST_HEAD(wait_queue[1]);
1793 } else {
1794 /* if the task was queued in the eternity queue, we must dequeue it */
1795 if (task->prev && (task->wq == LIST_HEAD(wait_queue[1]))) {
1796 task_delete(task);
1797 task->prev = NULL;
1798 list = task->wq = LIST_HEAD(wait_queue[0]);
1799 }
1800 }
1801
1802 /* next, test if the task was already in a list */
willy tarreau0f7af912005-12-17 12:21:26 +01001803 if (task->prev == NULL) {
1804 // start_from = list;
1805 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001806#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001807 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001808#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001809 /* insert the unlinked <task> into the list, searching back from the last entry */
1810 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1811 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001812#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001813 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001814#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001815 }
1816
1817 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1818 // start_from = start_from->next;
1819 // stats_tsk_nsrch++;
1820 // }
1821 }
1822 else if (task->prev == list ||
1823 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1824 start_from = task->next;
1825 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001826#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001827 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001828#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001829 return task; /* it's already in the right place */
1830 }
1831
willy tarreau750a4722005-12-17 13:21:24 +01001832#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001833 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001834#endif
1835
1836 /* if the task is not at the right place, there's little chance that
1837 * it has only shifted a bit, and it will nearly always be queued
1838 * at the end of the list because of constant timeouts
1839 * (observed in real case).
1840 */
1841#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1842 start_from = list->prev; /* assume we'll queue to the end of the list */
1843 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1844 start_from = start_from->prev;
1845#if STATTIME > 0
1846 stats_tsk_lsrch++;
1847#endif
1848 }
1849#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001850 /* insert the unlinked <task> into the list, searching after position <start_from> */
1851 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1852 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001853#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001854 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001855#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001856 }
willy tarreau750a4722005-12-17 13:21:24 +01001857#endif /* WE_REALLY_... */
1858
willy tarreau0f7af912005-12-17 12:21:26 +01001859 /* we need to unlink it now */
1860 task_delete(task);
1861 }
1862 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001863#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001864 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001865#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001866#ifdef LEFT_TO_TOP /* not very good */
1867 start_from = list;
1868 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1869 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001870#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001871 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001872#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001873 }
1874#else
1875 start_from = task->prev->prev; /* valid because of the previous test above */
1876 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1877 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001878#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001879 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001880#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001881 }
1882#endif
1883 /* we need to unlink it now */
1884 task_delete(task);
1885 }
1886 task->prev = start_from;
1887 task->next = start_from->next;
1888 task->next->prev = task;
1889 start_from->next = task;
1890 return task;
1891}
1892
1893
1894/*********************************************************************/
willy tarreau18a957c2006-04-12 19:26:23 +02001895/* pending connections queues **************************************/
1896/*********************************************************************/
1897
1898/*
willy tarreaudfece232006-05-02 00:19:57 +02001899 * Detaches pending connection <p>, decreases the pending count, and frees
1900 * the pending connection. The connection might have been queued to a specific
1901 * server as well as to the proxy. The session also gets marked unqueued.
willy tarreau18a957c2006-04-12 19:26:23 +02001902 */
willy tarreaudfece232006-05-02 00:19:57 +02001903static void pendconn_free(struct pendconn *p) {
1904 LIST_DEL(&p->list);
1905 p->sess->pend_pos = NULL;
1906 if (p->srv)
1907 p->srv->nbpend--;
1908 else
1909 p->sess->proxy->nbpend--;
willy tarreauf32f5242006-05-02 22:54:52 +02001910 p->sess->proxy->totpend--;
willy tarreaudfece232006-05-02 00:19:57 +02001911 pool_free(pendconn, p);
1912}
1913
1914/* Returns the first pending connection for server <s>, which may be NULL if
1915 * nothing is pending.
1916 */
1917static inline struct pendconn *pendconn_from_srv(struct server *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001918 if (!s->nbpend)
1919 return NULL;
1920
1921 return LIST_ELEM(s->pendconns.n, struct pendconn *, list);
1922}
1923
willy tarreaudfece232006-05-02 00:19:57 +02001924/* Returns the first pending connection for proxy <px>, which may be NULL if
1925 * nothing is pending.
willy tarreau18a957c2006-04-12 19:26:23 +02001926 */
willy tarreaudfece232006-05-02 00:19:57 +02001927static inline struct pendconn *pendconn_from_px(struct proxy *px) {
1928 if (!px->nbpend)
1929 return NULL;
1930
1931 return LIST_ELEM(px->pendconns.n, struct pendconn *, list);
willy tarreau18a957c2006-04-12 19:26:23 +02001932}
1933
willy tarreaubc2eda62006-05-04 15:16:23 +02001934/* Detaches the next pending connection from either a server or a proxy, and
1935 * returns its associated session. If no pending connection is found, NULL is
1936 * returned. Note that neither <srv> nor <px> can be NULL.
willy tarreau18a957c2006-04-12 19:26:23 +02001937 */
willy tarreaubc2eda62006-05-04 15:16:23 +02001938static struct session *pendconn_get_next_sess(struct server *srv, struct proxy *px) {
willy tarreau18a957c2006-04-12 19:26:23 +02001939 struct pendconn *p;
1940 struct session *sess;
1941
willy tarreaubc2eda62006-05-04 15:16:23 +02001942 p = pendconn_from_srv(srv);
willy tarreaudfece232006-05-02 00:19:57 +02001943 if (!p) {
willy tarreaubc2eda62006-05-04 15:16:23 +02001944 p = pendconn_from_px(px);
willy tarreaudfece232006-05-02 00:19:57 +02001945 if (!p)
1946 return NULL;
willy tarreaubc2eda62006-05-04 15:16:23 +02001947 p->sess->srv = srv;
willy tarreaudfece232006-05-02 00:19:57 +02001948 }
willy tarreau18a957c2006-04-12 19:26:23 +02001949 sess = p->sess;
1950 pendconn_free(p);
1951 return sess;
1952}
1953
willy tarreaudfece232006-05-02 00:19:57 +02001954/* Adds the session <sess> to the pending connection list of server <sess>->srv
1955 * or to the one of <sess>->proxy if srv is NULL. All counters and back pointers
1956 * are updated accordingly. Returns NULL if no memory is available, otherwise the
1957 * pendconn itself.
willy tarreau18a957c2006-04-12 19:26:23 +02001958 */
willy tarreaudfece232006-05-02 00:19:57 +02001959static struct pendconn *pendconn_add(struct session *sess) {
willy tarreau18a957c2006-04-12 19:26:23 +02001960 struct pendconn *p;
1961
1962 p = pool_alloc(pendconn);
1963 if (!p)
1964 return NULL;
1965
willy tarreau18a957c2006-04-12 19:26:23 +02001966 sess->pend_pos = p;
willy tarreaudfece232006-05-02 00:19:57 +02001967 p->sess = sess;
1968 p->srv = sess->srv;
1969 if (sess->srv) {
1970 LIST_ADDQ(&sess->srv->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001971 sess->logs.srv_queue_size += sess->srv->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001972 sess->srv->nbpend++;
willy tarreaucb406512006-05-18 00:52:35 +02001973 if (sess->srv->nbpend > sess->srv->nbpend_max)
1974 sess->srv->nbpend_max = sess->srv->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001975 } else {
1976 LIST_ADDQ(&sess->proxy->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001977 sess->logs.prx_queue_size += sess->proxy->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001978 sess->proxy->nbpend++;
willy tarreaucb406512006-05-18 00:52:35 +02001979 if (sess->proxy->nbpend > sess->proxy->nbpend_max)
1980 sess->proxy->nbpend_max = sess->proxy->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001981 }
willy tarreauf32f5242006-05-02 22:54:52 +02001982 sess->proxy->totpend++;
willy tarreau18a957c2006-04-12 19:26:23 +02001983 return p;
1984}
1985
willy tarreauf76e6ca2006-05-21 21:09:55 +02001986/* returns the effective dynamic maxconn for a server, considering the minconn
1987 * and the proxy's usage relative to its saturation.
1988 */
1989static unsigned int srv_dynamic_maxconn(struct server *s) {
1990 return s->minconn ?
1991 ((s->maxconn * s->proxy->nbconn / s->proxy->maxconn) < s->minconn) ? s->minconn :
1992 (s->maxconn * s->proxy->nbconn / s->proxy->maxconn) : s->maxconn;
1993}
1994
willy tarreau59a6cc22006-05-12 01:29:08 +02001995/* returns 0 if nothing has to be done for server <s> regarding queued connections,
1996 * and non-zero otherwise. Suited for and if/else usage.
1997 */
1998static inline int may_dequeue_tasks(struct server *s, struct proxy *p) {
1999 return (s && (s->nbpend || p->nbpend) &&
willy tarreauf76e6ca2006-05-21 21:09:55 +02002000 (!s->maxconn || s->cur_sess < srv_dynamic_maxconn(s)) &&
2001 s->queue_mgt);
willy tarreau59a6cc22006-05-12 01:29:08 +02002002}
2003
2004
2005
willy tarreau18a957c2006-04-12 19:26:23 +02002006/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +01002007/* more specific functions ***************************************/
2008/*********************************************************************/
2009
2010/* some prototypes */
2011static int maintain_proxies(void);
2012
willy tarreaub952e1d2005-12-18 01:31:20 +01002013/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01002014 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
2015 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01002016static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01002017#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002018 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
2019#else
willy tarreaua1598082005-12-17 13:08:06 +01002020#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002021 return getsockname(fd, (struct sockaddr *)sa, salen);
2022#else
2023 return -1;
2024#endif
2025#endif
2026}
2027
2028/*
2029 * frees the context associated to a session. It must have been removed first.
2030 */
willy tarreaudfece232006-05-02 00:19:57 +02002031static void session_free(struct session *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02002032 if (s->pend_pos)
2033 pendconn_free(s->pend_pos);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002034 if (s->req)
2035 pool_free(buffer, s->req);
2036 if (s->rep)
2037 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01002038
2039 if (s->rsp_cap != NULL) {
2040 struct cap_hdr *h;
2041 for (h = s->proxy->rsp_cap; h; h = h->next) {
2042 if (s->rsp_cap[h->index] != NULL)
2043 pool_free_to(h->pool, s->rsp_cap[h->index]);
2044 }
2045 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
2046 }
2047 if (s->req_cap != NULL) {
2048 struct cap_hdr *h;
2049 for (h = s->proxy->req_cap; h; h = h->next) {
2050 if (s->req_cap[h->index] != NULL)
2051 pool_free_to(h->pool, s->req_cap[h->index]);
2052 }
2053 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
2054 }
2055
willy tarreaua1598082005-12-17 13:08:06 +01002056 if (s->logs.uri)
2057 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01002058 if (s->logs.cli_cookie)
2059 pool_free(capture, s->logs.cli_cookie);
2060 if (s->logs.srv_cookie)
2061 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01002062
willy tarreau5cbea6f2005-12-17 12:48:26 +01002063 pool_free(session, s);
2064}
2065
willy tarreau0f7af912005-12-17 12:21:26 +01002066
2067/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01002068 * This function recounts the number of usable active and backup servers for
2069 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002070 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01002071 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002072static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002073 struct server *srv;
2074
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002075 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002076 for (srv = px->srv; srv != NULL; srv = srv->next) {
2077 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002078 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002079 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002080 px->tot_wbck += srv->eweight + 1;
2081 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002082 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002083 px->tot_wact += srv->eweight + 1;
2084 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01002085 }
2086 }
2087}
2088
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002089/* This function recomputes the server map for proxy px. It
2090 * relies on px->tot_wact and px->tot_wbck, so it must be
2091 * called after recount_servers(). It also expects px->srv_map
2092 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01002093 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002094static void recalc_server_map(struct proxy *px) {
2095 int o, tot, flag;
2096 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01002097
willy tarreau4c8c2b52006-03-24 19:36:41 +01002098 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002099 flag = SRV_RUNNING;
2100 tot = px->tot_wact;
2101 } else if (px->srv_bck) {
2102 flag = SRV_RUNNING | SRV_BACKUP;
2103 if (px->options & PR_O_USE_ALL_BK)
2104 tot = px->tot_wbck;
2105 else
2106 tot = 1; /* the first server is enough */
2107 } else {
2108 px->srv_map_sz = 0;
2109 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002110 }
Willy TARREAU3481c462006-03-01 22:37:57 +01002111
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002112 /* this algorithm gives priority to the first server, which means that
2113 * it will respect the declaration order for equivalent weights, and
2114 * that whatever the weights, the first server called will always be
2115 * the first declard. This is an important asumption for the backup
2116 * case, where we want the first server only.
2117 */
2118 for (cur = px->srv; cur; cur = cur->next)
2119 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002120
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002121 for (o = 0; o < tot; o++) {
2122 int max = 0;
2123 best = NULL;
2124 for (cur = px->srv; cur; cur = cur->next) {
2125 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
2126 int v;
2127
2128 /* If we are forced to return only one server, we don't want to
2129 * go further, because we would return the wrong one due to
2130 * divide overflow.
2131 */
2132 if (tot == 1) {
2133 best = cur;
2134 break;
2135 }
2136
2137 cur->wscore += cur->eweight + 1;
2138 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
2139 if (best == NULL || v > max) {
2140 max = v;
2141 best = cur;
2142 }
2143 }
2144 }
2145 px->srv_map[o] = best;
2146 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002147 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002148 px->srv_map_sz = tot;
2149}
Willy TARREAU3481c462006-03-01 22:37:57 +01002150
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002151/*
willy tarreau898db9d2006-04-12 20:29:08 +02002152 * This function tries to find a running server with free connection slots for
2153 * the proxy <px> following the round-robin method.
2154 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2155 * to point to the next server. If no valid server is found, NULL is returned.
2156 */
2157static inline struct server *get_server_rr_with_conns(struct proxy *px) {
2158 int newidx;
2159 struct server *srv;
2160
2161 if (px->srv_map_sz == 0)
2162 return NULL;
2163
2164 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2165 px->srv_rr_idx = 0;
2166 newidx = px->srv_rr_idx;
2167
2168 do {
2169 srv = px->srv_map[newidx++];
willy tarreauf76e6ca2006-05-21 21:09:55 +02002170 if (!srv->maxconn || srv->cur_sess < srv_dynamic_maxconn(srv)) {
willy tarreau898db9d2006-04-12 20:29:08 +02002171 px->srv_rr_idx = newidx;
2172 return srv;
2173 }
2174 if (newidx == px->srv_map_sz)
2175 newidx = 0;
2176 } while (newidx != px->srv_rr_idx);
2177
2178 return NULL;
2179}
2180
2181
2182/*
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002183 * This function tries to find a running server for the proxy <px> following
willy tarreau898db9d2006-04-12 20:29:08 +02002184 * the round-robin method.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002185 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2186 * to point to the next server. If no valid server is found, NULL is returned.
2187 */
2188static inline struct server *get_server_rr(struct proxy *px) {
2189 if (px->srv_map_sz == 0)
2190 return NULL;
2191
2192 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2193 px->srv_rr_idx = 0;
2194 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01002195}
2196
willy tarreau62084d42006-03-24 18:57:41 +01002197
2198/*
willy tarreau1a3442d2006-03-24 21:03:20 +01002199 * This function tries to find a running server for the proxy <px> following
2200 * the source hash method. Depending on the number of active/backup servers,
2201 * it will either look for active servers, or for backup servers.
2202 * If any server is found, it will be returned. If no valid server is found,
2203 * NULL is returned.
2204 */
2205static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002206 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01002207
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002208 if (px->srv_map_sz == 0)
2209 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01002210
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002211 l = h = 0;
willy tarreaucd655352006-04-29 12:11:46 +02002212 if (px->srv_act > 1 || (px->srv_act == 0 && px->srv_bck > 1)) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002213 while ((l + sizeof (int)) <= len) {
2214 h ^= ntohl(*(unsigned int *)(&addr[l]));
2215 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01002216 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002217 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01002218 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002219 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01002220}
2221
2222
2223/*
willy tarreaudfece232006-05-02 00:19:57 +02002224 * This function marks the session as 'assigned' in direct or dispatch modes,
2225 * or tries to assign one in balance mode, according to the algorithm. It does
2226 * nothing if the session had already been assigned a server.
2227 *
2228 * It may return :
willy tarreau000375f2006-05-09 23:15:58 +02002229 * SRV_STATUS_OK if everything is OK. s->srv will be valid.
2230 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
2231 * SRV_STATUS_FULL if all servers are saturated. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002232 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2233 *
2234 * Upon successful return, the session flag SN_ASSIGNED to indicate that it does
2235 * not need to be called anymore. This usually means that s->srv can be trusted
2236 * in balance and direct modes. This flag is not cleared, so it's to the caller
2237 * to clear it if required (eg: redispatch).
2238 *
willy tarreau0f7af912005-12-17 12:21:26 +01002239 */
willy tarreau0f7af912005-12-17 12:21:26 +01002240
willy tarreaudfece232006-05-02 00:19:57 +02002241int assign_server(struct session *s) {
willy tarreau12350152005-12-18 01:03:27 +01002242#ifdef DEBUG_FULL
willy tarreaudfece232006-05-02 00:19:57 +02002243 fprintf(stderr,"assign_server : s=%p\n",s);
willy tarreau12350152005-12-18 01:03:27 +01002244#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002245
willy tarreaudfece232006-05-02 00:19:57 +02002246 if (s->pend_pos)
2247 return SRV_STATUS_INTERNAL;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002248
willy tarreaudfece232006-05-02 00:19:57 +02002249 if (!(s->flags & SN_ASSIGNED)) {
2250 if ((s->proxy->options & PR_O_BALANCE) && !(s->flags & SN_DIRECT)) {
2251 if (!s->proxy->srv_act && !s->proxy->srv_bck)
2252 return SRV_STATUS_NOSRV;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002253
willy tarreaudfece232006-05-02 00:19:57 +02002254 if (s->proxy->options & PR_O_BALANCE_RR) {
2255 s->srv = get_server_rr_with_conns(s->proxy);
2256 if (!s->srv)
2257 return SRV_STATUS_FULL;
2258 }
2259 else if (s->proxy->options & PR_O_BALANCE_SH) {
2260 int len;
2261
2262 if (s->cli_addr.ss_family == AF_INET)
2263 len = 4;
2264 else if (s->cli_addr.ss_family == AF_INET6)
2265 len = 16;
2266 else /* unknown IP family */
2267 return SRV_STATUS_INTERNAL;
2268
2269 s->srv = get_server_sh(s->proxy,
2270 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2271 len);
2272 }
2273 else /* unknown balancing algorithm */
2274 return SRV_STATUS_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002275 }
willy tarreaudfece232006-05-02 00:19:57 +02002276 s->flags |= SN_ASSIGNED;
2277 }
2278 return SRV_STATUS_OK;
2279}
willy tarreau1a3442d2006-03-24 21:03:20 +01002280
willy tarreaudfece232006-05-02 00:19:57 +02002281/*
2282 * This function assigns a server address to a session, and sets SN_ADDR_SET.
2283 * The address is taken from the currently assigned server, or from the
2284 * dispatch or transparent address.
2285 *
2286 * It may return :
2287 * SRV_STATUS_OK if everything is OK.
2288 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2289 *
2290 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
2291 * not cleared, so it's to the caller to clear it if required.
2292 *
2293 */
2294int assign_server_address(struct session *s) {
2295#ifdef DEBUG_FULL
2296 fprintf(stderr,"assign_server_address : s=%p\n",s);
2297#endif
2298
2299 if (s->flags & SN_DIRECT || s->proxy->options & PR_O_BALANCE) {
2300 /* A server is necessarily known for this session */
2301 if (!(s->flags & SN_ASSIGNED))
2302 return SRV_STATUS_INTERNAL;
2303
2304 s->srv_addr = s->srv->addr;
willy tarreau1a3442d2006-03-24 21:03:20 +01002305
willy tarreaudfece232006-05-02 00:19:57 +02002306 /* if this server remaps proxied ports, we'll use
2307 * the port the client connected to with an offset. */
2308 if (s->srv->state & SRV_MAPPORTS) {
2309 struct sockaddr_in sockname;
2310 socklen_t namelen = sizeof(sockname);
2311
2312 if (!(s->proxy->options & PR_O_TRANSP) ||
2313 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2314 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2315 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
willy tarreau1a3442d2006-03-24 21:03:20 +01002316 }
willy tarreau0f7af912005-12-17 12:21:26 +01002317 }
willy tarreaua1598082005-12-17 13:08:06 +01002318 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002319 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002320 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002321 }
2322 else if (s->proxy->options & PR_O_TRANSP) {
2323 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002324 socklen_t salen = sizeof(s->srv_addr);
2325
willy tarreau5cbea6f2005-12-17 12:48:26 +01002326 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2327 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaudfece232006-05-02 00:19:57 +02002328 return SRV_STATUS_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002329 }
2330 }
willy tarreau0f7af912005-12-17 12:21:26 +01002331
willy tarreaudfece232006-05-02 00:19:57 +02002332 s->flags |= SN_ADDR_SET;
2333 return SRV_STATUS_OK;
2334}
willy tarreaua41a8b42005-12-17 14:02:24 +01002335
willy tarreaudfece232006-05-02 00:19:57 +02002336/* This function assigns a server to session <s> if required, and can add the
2337 * connection to either the assigned server's queue or to the proxy's queue.
2338 *
2339 * Returns :
2340 *
2341 * SRV_STATUS_OK if everything is OK.
willy tarreau000375f2006-05-09 23:15:58 +02002342 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002343 * SRV_STATUS_QUEUED if the connection has been queued.
2344 * SRV_STATUS_FULL if the server(s) is/are saturated and the
2345 * connection could not be queued.
2346 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2347 *
2348 */
2349int assign_server_and_queue(struct session *s) {
2350 struct pendconn *p;
2351 int err;
2352
2353 if (s->pend_pos)
2354 return SRV_STATUS_INTERNAL;
2355
2356 if (s->flags & SN_ASSIGNED) {
2357 /* a server does not need to be assigned, perhaps because we're in
2358 * direct mode, or in dispatch or transparent modes where the server
2359 * is not needed.
2360 */
2361 if (s->srv &&
willy tarreauf76e6ca2006-05-21 21:09:55 +02002362 s->srv->maxconn && s->srv->cur_sess >= srv_dynamic_maxconn(s->srv)) {
willy tarreaudfece232006-05-02 00:19:57 +02002363 p = pendconn_add(s);
2364 if (p)
2365 return SRV_STATUS_QUEUED;
2366 else
2367 return SRV_STATUS_FULL;
2368 }
2369 return SRV_STATUS_OK;
2370 }
2371
2372 /* a server needs to be assigned */
2373 err = assign_server(s);
2374 switch (err) {
2375 case SRV_STATUS_OK:
2376 /* in balance mode, we might have servers with connection limits */
willy tarreauf76e6ca2006-05-21 21:09:55 +02002377 if (s->srv &&
2378 s->srv->maxconn && s->srv->cur_sess >= srv_dynamic_maxconn(s->srv)) {
willy tarreaudfece232006-05-02 00:19:57 +02002379 p = pendconn_add(s);
2380 if (p)
2381 return SRV_STATUS_QUEUED;
2382 else
2383 return SRV_STATUS_FULL;
2384 }
2385 return SRV_STATUS_OK;
2386
2387 case SRV_STATUS_FULL:
2388 /* queue this session into the proxy's queue */
2389 p = pendconn_add(s);
2390 if (p)
2391 return SRV_STATUS_QUEUED;
2392 else
2393 return SRV_STATUS_FULL;
2394
2395 case SRV_STATUS_NOSRV:
2396 case SRV_STATUS_INTERNAL:
2397 return err;
2398 default:
2399 return SRV_STATUS_INTERNAL;
willy tarreaua41a8b42005-12-17 14:02:24 +01002400 }
willy tarreaudfece232006-05-02 00:19:57 +02002401}
2402
2403
2404/*
2405 * This function initiates a connection to the server assigned to this session
2406 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
2407 * It can return one of :
2408 * - SN_ERR_NONE if everything's OK
2409 * - SN_ERR_SRVTO if there are no more servers
2410 * - SN_ERR_SRVCL if the connection was refused by the server
2411 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
2412 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
2413 * - SN_ERR_INTERNAL for any other purely internal errors
2414 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
2415 */
2416int connect_server(struct session *s) {
2417 int fd, err;
2418
2419 if (!(s->flags & SN_ADDR_SET)) {
2420 err = assign_server_address(s);
2421 if (err != SRV_STATUS_OK)
2422 return SN_ERR_INTERNAL;
2423 }
willy tarreaua41a8b42005-12-17 14:02:24 +01002424
willy tarreau0f7af912005-12-17 12:21:26 +01002425 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002426 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002427
2428 if (errno == ENFILE)
2429 send_log(s->proxy, LOG_EMERG,
2430 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2431 s->proxy->id, maxfd);
2432 else if (errno == EMFILE)
2433 send_log(s->proxy, LOG_EMERG,
2434 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2435 s->proxy->id, maxfd);
2436 else if (errno == ENOBUFS || errno == ENOMEM)
2437 send_log(s->proxy, LOG_EMERG,
2438 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2439 s->proxy->id, maxfd);
2440 /* this is a resource error */
2441 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002442 }
2443
willy tarreau9fe663a2005-12-17 13:02:59 +01002444 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002445 /* do not log anything there, it's a normal condition when this option
2446 * is used to serialize connections to a server !
2447 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002448 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2449 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002450 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002451 }
2452
willy tarreau0f7af912005-12-17 12:21:26 +01002453 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2454 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002455 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002456 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002457 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002458 }
2459
willy tarreaub952e1d2005-12-18 01:31:20 +01002460 if (s->proxy->options & PR_O_TCP_SRV_KA)
2461 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2462
willy tarreau0174f312005-12-18 01:02:42 +01002463 /* allow specific binding :
2464 * - server-specific at first
2465 * - proxy-specific next
2466 */
2467 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2468 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2469 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2470 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2471 s->proxy->id, s->srv->id);
2472 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002473 send_log(s->proxy, LOG_EMERG,
2474 "Cannot bind to source address before connect() for server %s/%s.\n",
2475 s->proxy->id, s->srv->id);
2476 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002477 }
2478 }
2479 else if (s->proxy->options & PR_O_BIND_SRC) {
2480 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2481 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2482 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2483 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002484 send_log(s->proxy, LOG_EMERG,
2485 "Cannot bind to source address before connect() for server %s/%s.\n",
2486 s->proxy->id, s->srv->id);
2487 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002488 }
willy tarreaua1598082005-12-17 13:08:06 +01002489 }
2490
willy tarreaub1285d52005-12-18 01:20:14 +01002491 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2492 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2493
2494 if (errno == EAGAIN || errno == EADDRINUSE) {
2495 char *msg;
2496 if (errno == EAGAIN) /* no free ports left, try again later */
2497 msg = "no free ports";
2498 else
2499 msg = "local address already in use";
2500
2501 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002502 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002503 send_log(s->proxy, LOG_EMERG,
2504 "Connect() failed for server %s/%s: %s.\n",
2505 s->proxy->id, s->srv->id, msg);
2506 return SN_ERR_RESOURCE;
2507 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002508 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002509 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002510 return SN_ERR_SRVTO;
2511 } else {
2512 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002513 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002514 close(fd);
2515 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002516 }
2517 }
2518
willy tarreau5cbea6f2005-12-17 12:48:26 +01002519 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002520 fdtab[fd].read = &event_srv_read;
2521 fdtab[fd].write = &event_srv_write;
2522 fdtab[fd].state = FD_STCONN; /* connection in progress */
2523
2524 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002525#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2526 if (PrevReadEvent) {
2527 assert(!(FD_ISSET(fd, PrevReadEvent)));
2528 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2529 }
2530#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002531
2532 fd_insert(fd);
willy tarreaucb406512006-05-18 00:52:35 +02002533 if (s->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02002534 s->srv->cur_sess++;
willy tarreaucb406512006-05-18 00:52:35 +02002535 if (s->srv->cur_sess > s->srv->cur_sess_max)
2536 s->srv->cur_sess_max = s->srv->cur_sess;
2537 }
willy tarreau0f7af912005-12-17 12:21:26 +01002538
2539 if (s->proxy->contimeout)
2540 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2541 else
2542 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002543 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002544}
2545
2546/*
2547 * this function is called on a read event from a client socket.
2548 * It returns 0.
2549 */
2550int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002551 struct task *t = fdtab[fd].owner;
2552 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002553 struct buffer *b = s->req;
2554 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002555
willy tarreau12350152005-12-18 01:03:27 +01002556#ifdef DEBUG_FULL
2557 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2558#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002559
willy tarreau0f7af912005-12-17 12:21:26 +01002560 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002561#ifdef FILL_BUFFERS
2562 while (1)
2563#else
2564 do
2565#endif
2566 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002567 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2568 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002569 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002570 }
2571 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002572 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002573 }
2574 else {
2575 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002576 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2577 * since it means that the rewrite protection has been removed. This
2578 * implies that the if statement can be removed.
2579 */
2580 if (max > b->rlim - b->data)
2581 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002582 }
2583
2584 if (max == 0) { /* not anymore room to store data */
2585 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002586 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002587 }
2588
willy tarreau3242e862005-12-17 12:27:53 +01002589#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002590 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002591 int skerr;
2592 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002593
willy tarreau5cbea6f2005-12-17 12:48:26 +01002594 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2595 if (skerr)
2596 ret = -1;
2597 else
2598 ret = recv(fd, b->r, max, 0);
2599 }
willy tarreau3242e862005-12-17 12:27:53 +01002600#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002601 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002602#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002603 if (ret > 0) {
2604 b->r += ret;
2605 b->l += ret;
2606 s->res_cr = RES_DATA;
2607
2608 if (b->r == b->data + BUFSIZE) {
2609 b->r = b->data; /* wrap around the buffer */
2610 }
willy tarreaua1598082005-12-17 13:08:06 +01002611
2612 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002613 /* we hope to read more data or to get a close on next round */
2614 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002615 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002616 else if (ret == 0) {
2617 s->res_cr = RES_NULL;
2618 break;
2619 }
2620 else if (errno == EAGAIN) {/* ignore EAGAIN */
2621 break;
2622 }
2623 else {
2624 s->res_cr = RES_ERROR;
2625 fdtab[fd].state = FD_STERROR;
2626 break;
2627 }
2628 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002629#ifndef FILL_BUFFERS
2630 while (0);
2631#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002632 }
2633 else {
2634 s->res_cr = RES_ERROR;
2635 fdtab[fd].state = FD_STERROR;
2636 }
2637
willy tarreau5cbea6f2005-12-17 12:48:26 +01002638 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002639 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002640 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2641 else
2642 tv_eternity(&s->crexpire);
2643
2644 task_wakeup(&rq, t);
2645 }
willy tarreau0f7af912005-12-17 12:21:26 +01002646
willy tarreau0f7af912005-12-17 12:21:26 +01002647 return 0;
2648}
2649
2650
2651/*
2652 * this function is called on a read event from a server socket.
2653 * It returns 0.
2654 */
2655int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002656 struct task *t = fdtab[fd].owner;
2657 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002658 struct buffer *b = s->rep;
2659 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002660
willy tarreau12350152005-12-18 01:03:27 +01002661#ifdef DEBUG_FULL
2662 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2663#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002664
willy tarreau0f7af912005-12-17 12:21:26 +01002665 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002666#ifdef FILL_BUFFERS
2667 while (1)
2668#else
2669 do
2670#endif
2671 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002672 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2673 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002674 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002675 }
2676 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002677 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002678 }
2679 else {
2680 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002681 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2682 * since it means that the rewrite protection has been removed. This
2683 * implies that the if statement can be removed.
2684 */
2685 if (max > b->rlim - b->data)
2686 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002687 }
2688
2689 if (max == 0) { /* not anymore room to store data */
2690 FD_CLR(fd, StaticReadEvent);
2691 break;
2692 }
2693
willy tarreau3242e862005-12-17 12:27:53 +01002694#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002695 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002696 int skerr;
2697 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002698
willy tarreau5cbea6f2005-12-17 12:48:26 +01002699 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2700 if (skerr)
2701 ret = -1;
2702 else
2703 ret = recv(fd, b->r, max, 0);
2704 }
willy tarreau3242e862005-12-17 12:27:53 +01002705#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002706 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002707#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002708 if (ret > 0) {
2709 b->r += ret;
2710 b->l += ret;
2711 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002712
willy tarreau5cbea6f2005-12-17 12:48:26 +01002713 if (b->r == b->data + BUFSIZE) {
2714 b->r = b->data; /* wrap around the buffer */
2715 }
willy tarreaua1598082005-12-17 13:08:06 +01002716
2717 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002718 /* we hope to read more data or to get a close on next round */
2719 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002720 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002721 else if (ret == 0) {
2722 s->res_sr = RES_NULL;
2723 break;
2724 }
2725 else if (errno == EAGAIN) {/* ignore EAGAIN */
2726 break;
2727 }
2728 else {
2729 s->res_sr = RES_ERROR;
2730 fdtab[fd].state = FD_STERROR;
2731 break;
2732 }
2733 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002734#ifndef FILL_BUFFERS
2735 while (0);
2736#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002737 }
2738 else {
2739 s->res_sr = RES_ERROR;
2740 fdtab[fd].state = FD_STERROR;
2741 }
2742
willy tarreau5cbea6f2005-12-17 12:48:26 +01002743 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002744 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002745 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2746 else
2747 tv_eternity(&s->srexpire);
2748
2749 task_wakeup(&rq, t);
2750 }
willy tarreau0f7af912005-12-17 12:21:26 +01002751
willy tarreau0f7af912005-12-17 12:21:26 +01002752 return 0;
2753}
2754
2755/*
2756 * this function is called on a write event from a client socket.
2757 * It returns 0.
2758 */
2759int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002760 struct task *t = fdtab[fd].owner;
2761 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002762 struct buffer *b = s->rep;
2763 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002764
willy tarreau12350152005-12-18 01:03:27 +01002765#ifdef DEBUG_FULL
2766 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2767#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002768
2769 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002770 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002771 // max = BUFSIZE; BUG !!!!
2772 max = 0;
2773 }
2774 else if (b->r > b->w) {
2775 max = b->r - b->w;
2776 }
2777 else
2778 max = b->data + BUFSIZE - b->w;
2779
willy tarreau0f7af912005-12-17 12:21:26 +01002780 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002781 if (max == 0) {
2782 s->res_cw = RES_NULL;
2783 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002784 tv_eternity(&s->cwexpire);
2785 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002786 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002787 }
2788
willy tarreau3242e862005-12-17 12:27:53 +01002789#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002790 {
2791 int skerr;
2792 socklen_t lskerr = sizeof(skerr);
2793
2794 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2795 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002796 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002797 else
willy tarreau3242e862005-12-17 12:27:53 +01002798 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002799 }
willy tarreau3242e862005-12-17 12:27:53 +01002800#else
willy tarreau0f7af912005-12-17 12:21:26 +01002801 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002802#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002803
2804 if (ret > 0) {
2805 b->l -= ret;
2806 b->w += ret;
2807
2808 s->res_cw = RES_DATA;
2809
2810 if (b->w == b->data + BUFSIZE) {
2811 b->w = b->data; /* wrap around the buffer */
2812 }
2813 }
2814 else if (ret == 0) {
2815 /* nothing written, just make as if we were never called */
2816// s->res_cw = RES_NULL;
2817 return 0;
2818 }
2819 else if (errno == EAGAIN) /* ignore EAGAIN */
2820 return 0;
2821 else {
2822 s->res_cw = RES_ERROR;
2823 fdtab[fd].state = FD_STERROR;
2824 }
2825 }
2826 else {
2827 s->res_cw = RES_ERROR;
2828 fdtab[fd].state = FD_STERROR;
2829 }
2830
willy tarreaub1ff9db2005-12-17 13:51:03 +01002831 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002832 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002833 /* FIXME: to prevent the client from expiring read timeouts during writes,
2834 * we refresh it. A solution would be to merge read+write timeouts into a
2835 * unique one, although that needs some study particularly on full-duplex
2836 * TCP connections. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002837 s->crexpire = s->cwexpire;
2838 }
willy tarreau0f7af912005-12-17 12:21:26 +01002839 else
2840 tv_eternity(&s->cwexpire);
2841
willy tarreau5cbea6f2005-12-17 12:48:26 +01002842 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002843 return 0;
2844}
2845
2846
2847/*
2848 * this function is called on a write event from a server socket.
2849 * It returns 0.
2850 */
2851int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002852 struct task *t = fdtab[fd].owner;
2853 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002854 struct buffer *b = s->req;
2855 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002856
willy tarreau12350152005-12-18 01:03:27 +01002857#ifdef DEBUG_FULL
2858 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2859#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002860
2861 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002862 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002863 // max = BUFSIZE; BUG !!!!
2864 max = 0;
2865 }
2866 else if (b->r > b->w) {
2867 max = b->r - b->w;
2868 }
2869 else
2870 max = b->data + BUFSIZE - b->w;
2871
willy tarreau0f7af912005-12-17 12:21:26 +01002872 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002873 if (max == 0) {
2874 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002875 if (s->srv_state == SV_STCONN) {
2876 int skerr;
2877 socklen_t lskerr = sizeof(skerr);
2878 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2879 if (skerr) {
2880 s->res_sw = RES_ERROR;
2881 fdtab[fd].state = FD_STERROR;
2882 task_wakeup(&rq, t);
2883 tv_eternity(&s->swexpire);
2884 FD_CLR(fd, StaticWriteEvent);
2885 return 0;
2886 }
2887 }
2888
willy tarreau0f7af912005-12-17 12:21:26 +01002889 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002890 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002891 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002892 tv_eternity(&s->swexpire);
2893 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002894 return 0;
2895 }
2896
willy tarreau3242e862005-12-17 12:27:53 +01002897#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002898 {
2899 int skerr;
2900 socklen_t lskerr = sizeof(skerr);
2901 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2902 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002903 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002904 else
willy tarreau3242e862005-12-17 12:27:53 +01002905 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002906 }
willy tarreau3242e862005-12-17 12:27:53 +01002907#else
willy tarreau0f7af912005-12-17 12:21:26 +01002908 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002909#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002910 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002911 if (ret > 0) {
2912 b->l -= ret;
2913 b->w += ret;
2914
2915 s->res_sw = RES_DATA;
2916
2917 if (b->w == b->data + BUFSIZE) {
2918 b->w = b->data; /* wrap around the buffer */
2919 }
2920 }
2921 else if (ret == 0) {
2922 /* nothing written, just make as if we were never called */
2923 // s->res_sw = RES_NULL;
2924 return 0;
2925 }
2926 else if (errno == EAGAIN) /* ignore EAGAIN */
2927 return 0;
2928 else {
2929 s->res_sw = RES_ERROR;
2930 fdtab[fd].state = FD_STERROR;
2931 }
2932 }
2933 else {
2934 s->res_sw = RES_ERROR;
2935 fdtab[fd].state = FD_STERROR;
2936 }
2937
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002938 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2939 * otherwise it could loop indefinitely !
2940 */
2941 if (s->srv_state != SV_STCONN) {
2942 if (s->proxy->srvtimeout) {
2943 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002944 /* FIXME: to prevent the server from expiring read timeouts during writes,
2945 * we refresh it. A solution would be to merge read+write+connect timeouts
2946 * into a unique one since we don't mind expiring on read or write, and none
2947 * of them is enabled while waiting for connect(), although that needs some
2948 * study particularly on full-duplex TCP connections. */
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002949 s->srexpire = s->swexpire;
2950 }
2951 else
2952 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002953 }
willy tarreau0f7af912005-12-17 12:21:26 +01002954
willy tarreau5cbea6f2005-12-17 12:48:26 +01002955 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002956 return 0;
2957}
2958
2959
willy tarreaue0331262006-05-15 03:02:46 +02002960/* returns 1 if the buffer is empty, 0 otherwise */
2961static inline int buffer_isempty(struct buffer *buf) {
2962 return buf->l == 0;
2963}
2964
2965
2966/* returns 1 if the buffer is full, 0 otherwise */
2967static inline int buffer_isfull(struct buffer *buf) {
2968 return buf->l == BUFSIZE;
2969}
2970
2971
2972/* flushes any content from buffer <buf> */
2973void buffer_flush(struct buffer *buf) {
2974 buf->r = buf->h = buf->lr = buf->w = buf->data;
2975 buf->l = 0;
2976}
2977
2978
2979/* returns the maximum number of bytes writable at once in this buffer */
2980int buffer_max(struct buffer *buf) {
willy tarreaucb406512006-05-18 00:52:35 +02002981 if (buf->l == BUFSIZE)
2982 return 0;
2983 else if (buf->r >= buf->w)
willy tarreaue0331262006-05-15 03:02:46 +02002984 return buf->data + BUFSIZE - buf->r;
2985 else
2986 return buf->w - buf->r;
2987}
2988
2989
willy tarreau0f7af912005-12-17 12:21:26 +01002990/*
willy tarreaue0331262006-05-15 03:02:46 +02002991 * Tries to realign the given buffer, and returns how many bytes can be written
2992 * there at once without overwriting anything.
2993 */
2994int buffer_realign(struct buffer *buf) {
2995 if (buf->l == 0) {
2996 /* let's realign the buffer to optimize I/O */
willy tarreaucb406512006-05-18 00:52:35 +02002997 buf->r = buf->w = buf->h = buf->lr = buf->data;
willy tarreaue0331262006-05-15 03:02:46 +02002998 }
2999 return buffer_max(buf);
3000}
3001
3002
3003/* writes <len> bytes from message <msg> to buffer <buf>. Returns 0 in case of
3004 * success, or the number of bytes available otherwise.
willy tarreau1f431b52006-05-21 14:46:15 +02003005 * FIXME-20060521: handle unaligned data.
willy tarreaue0331262006-05-15 03:02:46 +02003006 */
3007int buffer_write(struct buffer *buf, const char *msg, int len) {
3008 int max;
3009
willy tarreaucb406512006-05-18 00:52:35 +02003010 max = buffer_realign(buf);
willy tarreaue0331262006-05-15 03:02:46 +02003011
3012 if (len > max)
3013 return max;
3014
3015 memcpy(buf->r, msg, len);
3016 buf->l += len;
3017 buf->r += len;
3018 if (buf->r == buf->data + BUFSIZE)
willy tarreaucb406512006-05-18 00:52:35 +02003019 buf->r = buf->data;
willy tarreaue0331262006-05-15 03:02:46 +02003020 return 0;
3021}
3022
3023
3024/*
willy tarreaue39cd132005-12-17 13:00:18 +01003025 * returns a message to the client ; the connection is shut down for read,
3026 * and the request is cleared so that no server connection can be initiated.
3027 * The client must be in a valid state for this (HEADER, DATA ...).
3028 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01003029 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01003030 */
3031void client_retnclose(struct session *s, int len, const char *msg) {
3032 FD_CLR(s->cli_fd, StaticReadEvent);
3033 FD_SET(s->cli_fd, StaticWriteEvent);
3034 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01003035 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01003036 shutdown(s->cli_fd, SHUT_RD);
3037 s->cli_state = CL_STSHUTR;
willy tarreaue0331262006-05-15 03:02:46 +02003038 buffer_flush(s->rep);
3039 buffer_write(s->rep, msg, len);
willy tarreaue39cd132005-12-17 13:00:18 +01003040 s->req->l = 0;
3041}
3042
3043
3044/*
3045 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01003046 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01003047 */
3048void client_return(struct session *s, int len, const char *msg) {
willy tarreaue0331262006-05-15 03:02:46 +02003049 buffer_flush(s->rep);
3050 buffer_write(s->rep, msg, len);
willy tarreaue39cd132005-12-17 13:00:18 +01003051 s->req->l = 0;
3052}
3053
willy tarreaue0331262006-05-15 03:02:46 +02003054/*
3055 * Produces data for the session <s> depending on its source. Expects to be
3056 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3057 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3058 * session, which it uses to keep on being called when there is free space in
3059 * the buffer, of simply by letting an empty buffer upon return. It returns 1
3060 * if it changes the session state from CL_STSHUTR, otherwise 0.
3061 */
3062int produce_content(struct session *s) {
3063 struct buffer *rep = s->rep;
3064 struct proxy *px;
3065 struct server *sv;
willy tarreaucb406512006-05-18 00:52:35 +02003066 int msglen;
willy tarreaue0331262006-05-15 03:02:46 +02003067
3068 if (s->data_source == DATA_SRC_NONE) {
3069 s->flags &= ~SN_SELF_GEN;
3070 return 1;
3071 }
3072 else if (s->data_source == DATA_SRC_STATS) {
willy tarreau1f431b52006-05-21 14:46:15 +02003073 msglen = 0;
3074
3075 if (s->data_state == DATA_ST_INIT) { /* the function had not been called yet */
3076 unsigned int up;
3077
willy tarreaue0331262006-05-15 03:02:46 +02003078 s->flags |= SN_SELF_GEN; // more data will follow
willy tarreau1f431b52006-05-21 14:46:15 +02003079
3080 /* send the start of the HTTP response */
3081 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003082 "HTTP/1.0 200 OK\r\n"
3083 "Cache-Control: no-cache\r\n"
3084 "Connection: close\r\n"
3085 "\r\n\r\n");
3086
3087 s->logs.status = 200;
3088 client_retnclose(s, msglen, trash); // send the start of the response.
willy tarreau1f431b52006-05-21 14:46:15 +02003089 msglen = 0;
3090
willy tarreaue0331262006-05-15 03:02:46 +02003091 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
3092 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
3093 if (!(s->flags & SN_FINST_MASK))
3094 s->flags |= SN_FINST_R;
3095
3096 /* WARNING! This must fit in the first buffer !!! */
willy tarreau1f431b52006-05-21 14:46:15 +02003097 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003098 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
3099 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
3100 "<style type=\"text/css\"><!--\n"
3101 "body {"
3102 " font-family: helvetica, arial;"
3103 " font-size: 12px;"
3104 " font-weight: normal;"
3105 " color: black;"
3106 " background: white;"
3107 "}\n"
3108 "td {"
3109 " font-size: 12px;"
willy tarreaucb406512006-05-18 00:52:35 +02003110 " align: center;"
willy tarreaue0331262006-05-15 03:02:46 +02003111 "}\n"
3112 "h1 {"
3113 " font-size: xx-large;"
3114 " margin-bottom: 0.5em;"
3115 "}\n"
3116 "h2 {"
3117 " font-family: helvetica, arial;"
3118 " font-size: x-large;"
3119 " font-weight: bold;"
3120 " font-style: italic;"
3121 " color: #6020a0;"
3122 " margin-top: 0em;"
3123 " margin-bottom: 0em;"
3124 "}\n"
3125 "h3 {"
3126 " font-family: helvetica, arial;"
3127 " font-size: 16px;"
3128 " font-weight: bold;"
3129 " color: #b00040;"
3130 " background: #e8e8d0;"
3131 " margin-top: 0em;"
3132 " margin-bottom: 0em;"
3133 "}\n"
3134 "li {"
3135 " margin-top: 0.25em;"
3136 " margin-right: 2em;"
3137 "}\n"
3138 ".hr {"
3139 " margin-top: 0.25em;"
3140 " border-color: black;"
3141 " border-bottom-style: solid;"
willy tarreaucb406512006-05-18 00:52:35 +02003142 "}\n"
3143 "table.tbl { border-collapse: collapse; border-width: 1px; border-style: solid; border-color: gray;}\n"
3144 "table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; border-color: gray; }\n"
3145 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray; }\n"
3146 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
3147 "table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n"
willy tarreaue0331262006-05-15 03:02:46 +02003148 "-->"
3149 "</style></head>");
3150
willy tarreaucb406512006-05-18 00:52:35 +02003151 if (buffer_write(rep, trash, msglen) != 0)
3152 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003153 msglen = 0;
willy tarreaue0331262006-05-15 03:02:46 +02003154
3155 up = (now.tv_sec - start_date.tv_sec);
3156
3157 /* WARNING! this has to fit the first packet too */
willy tarreau1f431b52006-05-21 14:46:15 +02003158 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003159 "<body><h1>" PRODUCT_NAME "</h1>\n"
3160 "<h2>Statistics Report for pid %d</h2>\n"
3161 "<hr width=\"100%%\" class=\"hr\">\n"
willy tarreau338be832006-05-21 08:58:06 +02003162 "<h3>&gt; General process information</h3>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003163 "<table border=0><tr><td align=\"left\">\n"
willy tarreaue0331262006-05-15 03:02:46 +02003164 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
3165 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
willy tarreau338be832006-05-21 08:58:06 +02003166 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
willy tarreaue0331262006-05-15 03:02:46 +02003167 "<b>maxsock = </b> %d<br>\n"
3168 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003169 "</td><td width=\"10%%\">\n"
3170 "</td><td align=\"right\">\n"
3171 "<table class=\"lgd\">"
3172 "<tr><td bgcolor=\"#C0FFC0\">&nbsp;</td><td style=\"border-style: none;\">active UP </td>"
3173 "<td bgcolor=\"#B0D0FF\">&nbsp;</td><td style=\"border-style: none;\">backup UP </td></tr>"
3174 "<tr><td bgcolor=\"#FFFFA0\"></td><td style=\"border-style: none;\">active UP, going down </td>"
3175 "<td bgcolor=\"#C060FF\"></td><td style=\"border-style: none;\">backup UP, going down </td></tr>"
3176 "<tr><td bgcolor=\"#FFD020\"></td><td style=\"border-style: none;\">active DOWN, going up </td>"
3177 "<td bgcolor=\"#FF80FF\"></td><td style=\"border-style: none;\">backup DOWN, going up </td></tr>"
3178 "<tr><td bgcolor=\"#FF9090\"></td><td style=\"border-style: none;\">active or backup DOWN &nbsp;</td>"
3179 "<td bgcolor=\"#E0E0E0\"></td><td style=\"border-style: none;\">not checked </td></tr>"
3180 "</table>\n"
3181 "</tr></table>\n"
willy tarreaue0331262006-05-15 03:02:46 +02003182 "",
3183 pid, pid, global.nbproc,
3184 up / 86400, (up % 86400) / 3600,
3185 (up % 3600) / 60, (up % 60),
willy tarreau338be832006-05-21 08:58:06 +02003186 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
3187 global.rlimit_memmax ? " MB" : "",
willy tarreaue0331262006-05-15 03:02:46 +02003188 global.rlimit_nofile,
3189 global.maxsock,
3190 global.maxconn,
3191 actconn
3192 );
willy tarreaucb406512006-05-18 00:52:35 +02003193
3194 if (buffer_write(rep, trash, msglen) != 0)
3195 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003196 msglen = 0;
3197
3198 s->data_state = DATA_ST_DATA;
3199 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
3200
willy tarreaue0331262006-05-15 03:02:46 +02003201 px = s->data_ctx.stats.px = proxy;
willy tarreau1f431b52006-05-21 14:46:15 +02003202 s->data_ctx.stats.px_st = DATA_ST_INIT;
willy tarreaue0331262006-05-15 03:02:46 +02003203 }
3204
3205 while (s->data_ctx.stats.px) {
willy tarreaucb406512006-05-18 00:52:35 +02003206 int dispatch_sess, dispatch_cum;
willy tarreau1f431b52006-05-21 14:46:15 +02003207 int failed_checks, down_trans;
willy tarreaue3b30652006-05-21 16:23:22 +02003208 int failed_secu, failed_conns, failed_resp;
willy tarreaucb406512006-05-18 00:52:35 +02003209
willy tarreau1f431b52006-05-21 14:46:15 +02003210 if (s->data_ctx.stats.px_st == DATA_ST_INIT) {
3211 /* we are on a new proxy */
willy tarreaue0331262006-05-15 03:02:46 +02003212 px = s->data_ctx.stats.px;
willy tarreau1f431b52006-05-21 14:46:15 +02003213
3214 /* skip the disabled proxies */
3215 if (px->state == PR_STSTOPPED)
3216 goto next_proxy;
3217
3218 if (s->proxy->uri_auth && s->proxy->uri_auth->scope) {
3219 /* we have a limited scope, we have to check the proxy name */
3220 struct stat_scope *scope;
3221 int len;
3222
3223 len = strlen(px->id);
3224 scope = s->proxy->uri_auth->scope;
3225
3226 while (scope) {
3227 /* match exact proxy name */
3228 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
3229 break;
3230
3231 /* match '.' which means 'self' proxy */
3232 if (!strcmp(scope->px_id, ".") && px == s->proxy)
3233 break;
3234 scope = scope->next;
3235 }
3236
3237 /* proxy name not found */
3238 if (scope == NULL)
3239 goto next_proxy;
3240 }
3241
3242 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003243 "<h3>&gt; Proxy instance %s : "
3244 "%d conns (maxconn=%d), %d queued (%d unassigned), %d total conns</h3>\n"
3245 "",
3246 px->id,
3247 px->nbconn, px->maxconn, px->totpend, px->nbpend, px->cum_conn);
3248
3249 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue3b30652006-05-21 16:23:22 +02003250 "<table cols=\"16\" class=\"tbl\">\n"
willy tarreaucb406512006-05-18 00:52:35 +02003251 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
3252 "<th colspan=5>Server</th>"
3253 "<th colspan=2>Queue</th>"
3254 "<th colspan=4>Sessions</th>"
willy tarreaue3b30652006-05-21 16:23:22 +02003255 "<th colspan=5>Errors</th></tr>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003256 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
3257 "<th>Name</th><th>Weight</th><th>Status</th><th>Act.</th><th>Bck.</th>"
3258 "<th>Curr.</th><th>Max.</th>"
3259 "<th>Curr.</th><th>Max.</th><th>Limit</th><th>Cumul.</th>"
willy tarreaue3b30652006-05-21 16:23:22 +02003260 "<th>Conn.</th><th>Resp.</th><th>Sec.</th><th>Check</th><th>Down</th></tr>\n");
willy tarreaue0331262006-05-15 03:02:46 +02003261
3262 if (buffer_write(rep, trash, msglen) != 0)
3263 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003264 msglen = 0;
3265
willy tarreaue0331262006-05-15 03:02:46 +02003266 s->data_ctx.stats.sv = px->srv;
willy tarreau1f431b52006-05-21 14:46:15 +02003267 s->data_ctx.stats.px_st = DATA_ST_DATA;
willy tarreaue0331262006-05-15 03:02:46 +02003268 }
3269
willy tarreaucb406512006-05-18 00:52:35 +02003270 px = s->data_ctx.stats.px;
3271
willy tarreau1f431b52006-05-21 14:46:15 +02003272 /* stats.sv has been initialized above */
willy tarreaue0331262006-05-15 03:02:46 +02003273 while (s->data_ctx.stats.sv != NULL) {
willy tarreaucb406512006-05-18 00:52:35 +02003274 static char *act_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FFD020", /*failing*/"#FFFFA0", /*up*/"#C0FFC0", /*unchecked*/"#E0E0E0" };
3275 static char *bck_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FF80ff", /*failing*/"#C060FF", /*up*/"#B0D0FF", /*unchecked*/"#E0E0E0" };
3276 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
3277 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP */
3278
willy tarreaue0331262006-05-15 03:02:46 +02003279 sv = s->data_ctx.stats.sv;
willy tarreaucb406512006-05-18 00:52:35 +02003280
willy tarreaucb406512006-05-18 00:52:35 +02003281 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
3282 if (!(sv->state & SRV_CHECKED))
3283 sv_state = 4;
3284 else if (sv->state & SRV_RUNNING)
3285 if (sv->health == sv->rise + sv->fall - 1)
3286 sv_state = 3; /* UP */
3287 else
3288 sv_state = 2; /* going down */
3289 else
3290 if (sv->health)
3291 sv_state = 1; /* going up */
3292 else
3293 sv_state = 0; /* DOWN */
3294
3295 /* name, weight */
willy tarreau1f431b52006-05-21 14:46:15 +02003296 msglen += snprintf(trash, sizeof(trash),
willy tarreaucb406512006-05-18 00:52:35 +02003297 "<tr align=center bgcolor=\"%s\"><td>%s</td><td>%d</td><td>",
3298 (sv->state & SRV_BACKUP) ? bck_tab_bg[sv_state] : act_tab_bg[sv_state],
3299 sv->id, sv->uweight+1);
3300 /* status */
3301 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, srv_hlt_st[sv_state],
3302 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
3303 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
3304
3305 /* act, bck */
3306 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3307 "</td><td>%s</td><td>%s</td>",
willy tarreaue0331262006-05-15 03:02:46 +02003308 (sv->state & SRV_BACKUP) ? "-" : "Y",
3309 (sv->state & SRV_BACKUP) ? "Y" : "-");
willy tarreaucb406512006-05-18 00:52:35 +02003310
3311 /* queue : current, max */
3312 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3313 "<td align=right>%d</td><td align=right>%d</td>",
3314 sv->nbpend, sv->nbpend_max);
3315
3316 /* sessions : current, max, limit, cumul */
3317 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3318 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>",
3319 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess);
3320
willy tarreaue3b30652006-05-21 16:23:22 +02003321 /* errors : connect, response, security */
3322 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3323 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3324 sv->failed_conns, sv->failed_resp, sv->failed_secu);
3325
3326 /* check failures : unique, fatal */
willy tarreau338be832006-05-21 08:58:06 +02003327 if (sv->state & SRV_CHECKED)
3328 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3329 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3330 sv->failed_checks, sv->down_trans);
3331 else
3332 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3333 "<td align=right>-</td><td align=right>-</td></tr>\n");
willy tarreaucb406512006-05-18 00:52:35 +02003334
willy tarreau1f431b52006-05-21 14:46:15 +02003335 if (buffer_write(rep, trash, msglen) != 0)
3336 return 0;
3337 msglen = 0;
3338
3339 s->data_ctx.stats.sv = sv->next;
3340 } /* while sv */
3341
3342 /* now we are past the last server, we'll dump information about the dispatcher */
3343
3344 /* We have to count down from the proxy to the servers to tell how
3345 * many sessions are on the dispatcher, and how many checks have
3346 * failed. We cannot count this during the servers dump because it
3347 * might be interrupted multiple times.
3348 */
3349 dispatch_sess = px->nbconn;
willy tarreaue3b30652006-05-21 16:23:22 +02003350 dispatch_cum = px->cum_conn;
3351 failed_secu = px->failed_secu;
3352 failed_conns = px->failed_conns;
3353 failed_resp = px->failed_resp;
willy tarreau1f431b52006-05-21 14:46:15 +02003354 failed_checks = down_trans = 0;
3355
3356 sv = px->srv;
3357 while (sv) {
3358 dispatch_sess -= sv->cur_sess;
3359 dispatch_cum -= sv->cum_sess;
willy tarreaue3b30652006-05-21 16:23:22 +02003360 failed_conns -= sv->failed_conns;
3361 failed_resp -= sv->failed_resp;
3362 failed_secu -= sv->failed_secu;
3363 if (sv->state & SRV_CHECKED) {
3364 failed_checks += sv->failed_checks;
3365 down_trans += sv->down_trans;
3366 }
willy tarreaue0331262006-05-15 03:02:46 +02003367 sv = sv->next;
willy tarreau1f431b52006-05-21 14:46:15 +02003368 }
willy tarreaucb406512006-05-18 00:52:35 +02003369
willy tarreau1f431b52006-05-21 14:46:15 +02003370 /* name, weight, status, act, bck */
3371 msglen += snprintf(trash + msglen, sizeof(trash),
3372 "<tr align=center bgcolor=\"#e8e8d0\">"
3373 "<td>Dispatcher</td><td>-</td>"
3374 "<td>%s</td><td>-</td><td>-</td>",
3375 px->state == PR_STRUN ? "UP" : "DOWN");
willy tarreaucb406512006-05-18 00:52:35 +02003376
willy tarreau1f431b52006-05-21 14:46:15 +02003377 /* queue : current, max */
3378 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3379 "<td align=right>%d</td><td align=right>%d</td>",
3380 px->nbpend, px->nbpend_max);
willy tarreaucb406512006-05-18 00:52:35 +02003381
willy tarreau1f431b52006-05-21 14:46:15 +02003382 /* sessions : current, max, limit, cumul. */
3383 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3384 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>",
3385 dispatch_sess, px->nbconn_max, px->maxconn, dispatch_cum);
willy tarreaucb406512006-05-18 00:52:35 +02003386
willy tarreaue3b30652006-05-21 16:23:22 +02003387 /* errors : connect, response, security */
3388 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3389 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3390 failed_conns, failed_resp, failed_secu);
3391
3392 /* check failures : unique, fatal */
willy tarreau1f431b52006-05-21 14:46:15 +02003393 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3394 "<td align=right>-</td><td align=right>-</td></tr>\n");
willy tarreaucb406512006-05-18 00:52:35 +02003395
willy tarreaucb406512006-05-18 00:52:35 +02003396
willy tarreau1f431b52006-05-21 14:46:15 +02003397 /* now the summary for the whole proxy */
3398 /* name, weight, status, act, bck */
3399 msglen += snprintf(trash + msglen, sizeof(trash),
3400 "<tr align=center style=\"color: #ffff80; background: #20C0C0;\">"
3401 "<td><b>Total</b></td><td>-</td>"
3402 "<td><b>%s</b></td><td><b>%d</b></td><td><b>%d</b></td>",
3403 (px->state == PR_STRUN && ((px->srv == NULL) || px->srv_act || px->srv_bck)) ? "UP" : "DOWN",
3404 px->srv_act, px->srv_bck);
willy tarreaucb406512006-05-18 00:52:35 +02003405
willy tarreau1f431b52006-05-21 14:46:15 +02003406 /* queue : current, max */
3407 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3408 "<td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
3409 px->totpend, px->nbpend_max);
willy tarreaucb406512006-05-18 00:52:35 +02003410
willy tarreau1f431b52006-05-21 14:46:15 +02003411 /* sessions : current, max, limit, cumul */
3412 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3413 "<td align=right><b>%d</b></td><td align=right><b>%d</b></td><td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
3414 px->nbconn, px->nbconn_max, px->maxconn, px->cum_conn);
willy tarreaucb406512006-05-18 00:52:35 +02003415
willy tarreaue3b30652006-05-21 16:23:22 +02003416 /* errors : connect, response, security */
3417 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3418 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3419 px->failed_conns, px->failed_resp, px->failed_secu);
3420
3421 /* check failures : unique, fatal */
willy tarreau1f431b52006-05-21 14:46:15 +02003422 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3423 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3424 failed_checks, down_trans);
willy tarreaucb406512006-05-18 00:52:35 +02003425
willy tarreau1f431b52006-05-21 14:46:15 +02003426 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, "</table><p>\n");
3427
3428 if (buffer_write(rep, trash, msglen) != 0)
3429 return 0;
3430 msglen = 0;
3431
3432 s->data_ctx.stats.px_st = DATA_ST_INIT;
3433 next_proxy:
3434 s->data_ctx.stats.px = px->next;
willy tarreaucb406512006-05-18 00:52:35 +02003435 } /* proxy loop */
willy tarreaue0331262006-05-15 03:02:46 +02003436 /* here, we just have reached the sv == NULL and px == NULL */
3437 s->flags &= ~SN_SELF_GEN;
3438 return 1;
3439 }
3440 else {
3441 /* unknown data source */
3442 s->logs.status = 500;
3443 client_retnclose(s, s->proxy->errmsg.len500, s->proxy->errmsg.msg500);
3444 if (!(s->flags & SN_ERR_MASK))
3445 s->flags |= SN_ERR_PRXCOND;
3446 if (!(s->flags & SN_FINST_MASK))
3447 s->flags |= SN_FINST_R;
3448 s->flags &= SN_SELF_GEN;
3449 return 1;
3450 }
3451}
3452
3453
willy tarreau9fe663a2005-12-17 13:02:59 +01003454/*
3455 * send a log for the session when we have enough info about it
3456 */
3457void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003458 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01003459 struct proxy *p = s->proxy;
3460 int log;
3461 char *uri;
3462 char *pxid;
3463 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01003464 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01003465
3466 /* This is a first attempt at a better logging system.
3467 * For now, we rely on send_log() to provide the date, although it obviously
3468 * is the date of the log and not of the request, and most fields are not
3469 * computed.
3470 */
3471
willy tarreaua1598082005-12-17 13:08:06 +01003472 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01003473
willy tarreau8a86dbf2005-12-18 00:45:59 +01003474 if (s->cli_addr.ss_family == AF_INET)
3475 inet_ntop(AF_INET,
3476 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3477 pn, sizeof(pn));
3478 else
3479 inet_ntop(AF_INET6,
3480 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3481 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01003482
willy tarreauc1cae632005-12-17 14:12:23 +01003483 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01003484 pxid = p->id;
willy tarreau8cd31142006-05-21 22:08:00 +02003485 srv = (p->to_log & LW_SVID) ?
3486 (s->data_source != DATA_SRC_STATS) ?
3487 (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "<STATS>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01003488
willy tarreauc1cae632005-12-17 14:12:23 +01003489 tm = localtime(&s->logs.tv_accept.tv_sec);
3490 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01003491 char tmpline[MAX_SYSLOG_LEN], *h;
3492 int hdr;
3493
3494 h = tmpline;
3495 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
3496 *(h++) = ' ';
3497 *(h++) = '{';
3498 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
3499 if (hdr)
3500 *(h++) = '|';
3501 if (s->req_cap[hdr] != NULL)
3502 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
3503 }
3504 *(h++) = '}';
3505 }
3506
3507 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
3508 *(h++) = ' ';
3509 *(h++) = '{';
3510 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
3511 if (hdr)
3512 *(h++) = '|';
3513 if (s->rsp_cap[hdr] != NULL)
3514 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
3515 }
3516 *(h++) = '}';
3517 }
3518
3519 if (h < tmpline + sizeof(tmpline) - 4) {
3520 *(h++) = ' ';
3521 *(h++) = '"';
3522 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
3523 *(h++) = '"';
3524 }
3525 *h = '\0';
3526
willy tarreau5e69b162006-05-12 19:49:37 +02003527 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 +01003528 pn,
3529 (s->cli_addr.ss_family == AF_INET) ?
3530 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3531 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01003532 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3533 tm->tm_hour, tm->tm_min, tm->tm_sec,
3534 pxid, srv,
3535 s->logs.t_request,
willy tarreauf32f5242006-05-02 22:54:52 +02003536 (s->logs.t_queue >= 0) ? s->logs.t_queue - s->logs.t_request : -1,
3537 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreaua1598082005-12-17 13:08:06 +01003538 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003539 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3540 s->logs.status,
3541 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01003542 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
3543 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01003544 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
3545 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
3546 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
3547 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau5e69b162006-05-12 19:49:37 +02003548 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3549 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01003550 }
3551 else {
willy tarreau5f15c552006-05-13 18:37:04 +02003552 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 +01003553 pn,
3554 (s->cli_addr.ss_family == AF_INET) ?
3555 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3556 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01003557 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3558 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01003559 pxid, srv,
willy tarreau5f15c552006-05-13 18:37:04 +02003560 (s->logs.t_queue >= 0) ? s->logs.t_queue : -1,
3561 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003562 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3563 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01003564 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01003565 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreau5e69b162006-05-12 19:49:37 +02003566 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3567 s->logs.srv_queue_size, s->logs.prx_queue_size);
willy tarreaua1598082005-12-17 13:08:06 +01003568 }
3569
3570 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003571}
3572
willy tarreaue39cd132005-12-17 13:00:18 +01003573
3574/*
willy tarreau0f7af912005-12-17 12:21:26 +01003575 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01003576 * to an accept. It tries to accept as many connections as possible.
3577 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01003578 */
3579int event_accept(int fd) {
3580 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003581 struct session *s;
3582 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01003583 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01003584 int max_accept;
3585
3586 if (global.nbproc > 1)
3587 max_accept = 8; /* let other processes catch some connections too */
3588 else
3589 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003590
willy tarreauc2becdc2006-03-19 19:36:48 +01003591 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003592 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003593 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01003594
willy tarreaub1285d52005-12-18 01:20:14 +01003595 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
3596 switch (errno) {
3597 case EAGAIN:
3598 case EINTR:
3599 case ECONNABORTED:
3600 return 0; /* nothing more to accept */
3601 case ENFILE:
3602 send_log(p, LOG_EMERG,
3603 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
3604 p->id, maxfd);
3605 return 0;
3606 case EMFILE:
3607 send_log(p, LOG_EMERG,
3608 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
3609 p->id, maxfd);
3610 return 0;
3611 case ENOBUFS:
3612 case ENOMEM:
3613 send_log(p, LOG_EMERG,
3614 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
3615 p->id, maxfd);
3616 return 0;
3617 default:
3618 return 0;
3619 }
3620 }
willy tarreau0f7af912005-12-17 12:21:26 +01003621
willy tarreau5cbea6f2005-12-17 12:48:26 +01003622 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
3623 Alert("out of memory in event_accept().\n");
3624 FD_CLR(fd, StaticReadEvent);
3625 p->state = PR_STIDLE;
3626 close(cfd);
3627 return 0;
3628 }
willy tarreau0f7af912005-12-17 12:21:26 +01003629
willy tarreaub1285d52005-12-18 01:20:14 +01003630 /* if this session comes from a known monitoring system, we want to ignore
3631 * it as soon as possible, which means closing it immediately for TCP.
3632 */
3633 s->flags = 0;
3634 if (addr.ss_family == AF_INET &&
3635 p->mon_mask.s_addr &&
3636 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
3637 if (p->mode == PR_MODE_TCP) {
3638 close(cfd);
3639 pool_free(session, s);
3640 continue;
3641 }
3642 s->flags |= SN_MONITOR;
3643 }
3644
willy tarreau5cbea6f2005-12-17 12:48:26 +01003645 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3646 Alert("out of memory in event_accept().\n");
3647 FD_CLR(fd, StaticReadEvent);
3648 p->state = PR_STIDLE;
3649 close(cfd);
3650 pool_free(session, s);
3651 return 0;
3652 }
willy tarreau0f7af912005-12-17 12:21:26 +01003653
willy tarreau5cbea6f2005-12-17 12:48:26 +01003654 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01003655 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003656 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
3657 close(cfd);
3658 pool_free(task, t);
3659 pool_free(session, s);
3660 return 0;
3661 }
willy tarreau0f7af912005-12-17 12:21:26 +01003662
willy tarreau5cbea6f2005-12-17 12:48:26 +01003663 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
3664 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
3665 (char *) &one, sizeof(one)) == -1)) {
3666 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
3667 close(cfd);
3668 pool_free(task, t);
3669 pool_free(session, s);
3670 return 0;
3671 }
willy tarreau0f7af912005-12-17 12:21:26 +01003672
willy tarreaub952e1d2005-12-18 01:31:20 +01003673 if (p->options & PR_O_TCP_CLI_KA)
3674 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
3675
willy tarreau9fe663a2005-12-17 13:02:59 +01003676 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02003677 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
willy tarreau9fe663a2005-12-17 13:02:59 +01003678 t->state = TASK_IDLE;
3679 t->process = process_session;
3680 t->context = s;
3681
3682 s->task = t;
3683 s->proxy = p;
3684 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
3685 s->srv_state = SV_STIDLE;
3686 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01003687
willy tarreau9fe663a2005-12-17 13:02:59 +01003688 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
3689 s->cli_fd = cfd;
3690 s->srv_fd = -1;
willy tarreau9e138862006-05-14 23:06:28 +02003691 s->req_line.len = -1;
3692 s->auth_hdr.len = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003693 s->srv = NULL;
Willy TARREAU1a71cc12006-05-14 09:10:03 +02003694 s->pend_pos = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01003695 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01003696
willy tarreaub1285d52005-12-18 01:20:14 +01003697 if (s->flags & SN_MONITOR)
3698 s->logs.logwait = 0;
3699 else
3700 s->logs.logwait = p->to_log;
3701
willy tarreaua1598082005-12-17 13:08:06 +01003702 s->logs.tv_accept = now;
3703 s->logs.t_request = -1;
willy tarreauf32f5242006-05-02 22:54:52 +02003704 s->logs.t_queue = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003705 s->logs.t_connect = -1;
3706 s->logs.t_data = -1;
3707 s->logs.t_close = 0;
3708 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01003709 s->logs.cli_cookie = NULL;
3710 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01003711 s->logs.status = -1;
3712 s->logs.bytes = 0;
willy tarreau5e69b162006-05-12 19:49:37 +02003713 s->logs.prx_queue_size = 0; /* we get the number of pending conns before us */
3714 s->logs.srv_queue_size = 0; /* we will get this number soon */
willy tarreau9fe663a2005-12-17 13:02:59 +01003715
willy tarreaue0331262006-05-15 03:02:46 +02003716 s->data_source = DATA_SRC_NONE;
willy tarreaue0331262006-05-15 03:02:46 +02003717
willy tarreau2f6ba652005-12-17 13:57:42 +01003718 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02003719 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01003720
willy tarreau4302f492005-12-18 01:00:37 +01003721 if (p->nb_req_cap > 0) {
3722 if ((s->req_cap =
3723 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
3724 == NULL) { /* no memory */
3725 close(cfd); /* nothing can be done for this fd without memory */
3726 pool_free(task, t);
3727 pool_free(session, s);
3728 return 0;
3729 }
3730 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
3731 }
3732 else
3733 s->req_cap = NULL;
3734
3735 if (p->nb_rsp_cap > 0) {
3736 if ((s->rsp_cap =
3737 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
3738 == NULL) { /* no memory */
3739 if (s->req_cap != NULL)
3740 pool_free_to(p->req_cap_pool, s->req_cap);
3741 close(cfd); /* nothing can be done for this fd without memory */
3742 pool_free(task, t);
3743 pool_free(session, s);
3744 return 0;
3745 }
3746 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
3747 }
3748 else
3749 s->rsp_cap = NULL;
3750
willy tarreau5cbea6f2005-12-17 12:48:26 +01003751 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
3752 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003753 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003754 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01003755
willy tarreau8a86dbf2005-12-18 00:45:59 +01003756 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003757 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003758 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003759 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01003760
willy tarreau9fe663a2005-12-17 13:02:59 +01003761 if (p->to_log) {
3762 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01003763 if (s->logs.logwait & LW_CLIP)
3764 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01003765 sess_log(s);
3766 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01003767 else if (s->cli_addr.ss_family == AF_INET) {
3768 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
3769 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
3770 sn, sizeof(sn)) &&
3771 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3772 pn, sizeof(pn))) {
3773 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3774 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
3775 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
3776 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3777 }
3778 }
3779 else {
3780 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
3781 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
3782 sn, sizeof(sn)) &&
3783 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
3784 pn, sizeof(pn))) {
3785 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3786 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
3787 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
3788 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3789 }
3790 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003791 }
willy tarreau0f7af912005-12-17 12:21:26 +01003792
willy tarreau982249e2005-12-18 00:57:06 +01003793 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01003794 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003795 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01003796 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01003797 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003798 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003799 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01003800 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01003801
willy tarreau8a86dbf2005-12-18 00:45:59 +01003802 if (s->cli_addr.ss_family == AF_INET) {
3803 char pn[INET_ADDRSTRLEN];
3804 inet_ntop(AF_INET,
3805 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3806 pn, sizeof(pn));
3807
3808 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3809 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3810 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
3811 }
3812 else {
3813 char pn[INET6_ADDRSTRLEN];
3814 inet_ntop(AF_INET6,
3815 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3816 pn, sizeof(pn));
3817
3818 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3819 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3820 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3821 }
3822
willy tarreauef900ab2005-12-17 12:52:52 +01003823 write(1, trash, len);
3824 }
willy tarreau0f7af912005-12-17 12:21:26 +01003825
willy tarreau5cbea6f2005-12-17 12:48:26 +01003826 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003827 if (s->rsp_cap != NULL)
3828 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3829 if (s->req_cap != NULL)
3830 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003831 close(cfd); /* nothing can be done for this fd without memory */
3832 pool_free(task, t);
3833 pool_free(session, s);
3834 return 0;
3835 }
willy tarreau4302f492005-12-18 01:00:37 +01003836
willy tarreau5cbea6f2005-12-17 12:48:26 +01003837 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003838 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003839 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3840 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003841 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003842 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003843
willy tarreau5cbea6f2005-12-17 12:48:26 +01003844 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3845 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003846 if (s->rsp_cap != NULL)
3847 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3848 if (s->req_cap != NULL)
3849 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003850 close(cfd); /* nothing can be done for this fd without memory */
3851 pool_free(task, t);
3852 pool_free(session, s);
3853 return 0;
3854 }
3855 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003856 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003857 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 +01003858
willy tarreau5cbea6f2005-12-17 12:48:26 +01003859 fdtab[cfd].read = &event_cli_read;
3860 fdtab[cfd].write = &event_cli_write;
3861 fdtab[cfd].owner = t;
3862 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003863
willy tarreaub1285d52005-12-18 01:20:14 +01003864 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3865 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3866 /* Either we got a request from a monitoring system on an HTTP instance,
3867 * or we're in health check mode with the 'httpchk' option enabled. In
3868 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3869 */
3870 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3871 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3872 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003873 }
3874 else {
3875 FD_SET(cfd, StaticReadEvent);
3876 }
3877
willy tarreaub952e1d2005-12-18 01:31:20 +01003878#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3879 if (PrevReadEvent) {
3880 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3881 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3882 }
3883#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003884 fd_insert(cfd);
3885
3886 tv_eternity(&s->cnexpire);
3887 tv_eternity(&s->srexpire);
3888 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003889 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003890 tv_eternity(&s->cwexpire);
3891
willy tarreaub1285d52005-12-18 01:20:14 +01003892 if (s->proxy->clitimeout) {
3893 if (FD_ISSET(cfd, StaticReadEvent))
3894 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3895 if (FD_ISSET(cfd, StaticWriteEvent))
3896 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3897 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003898
willy tarreaub1285d52005-12-18 01:20:14 +01003899 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003900
3901 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003902
3903 if (p->mode != PR_MODE_HEALTH)
3904 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003905
3906 p->nbconn++;
willy tarreaucb406512006-05-18 00:52:35 +02003907 if (p->nbconn > p->nbconn_max)
3908 p->nbconn_max = p->nbconn;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003909 actconn++;
3910 totalconn++;
3911
willy tarreaub952e1d2005-12-18 01:31:20 +01003912 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003913 } /* end of while (p->nbconn < p->maxconn) */
3914 return 0;
3915}
willy tarreau0f7af912005-12-17 12:21:26 +01003916
willy tarreau0f7af912005-12-17 12:21:26 +01003917
willy tarreau5cbea6f2005-12-17 12:48:26 +01003918/*
3919 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003920 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3921 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003922 * or -1 if an error occured.
3923 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003924int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003925 struct task *t = fdtab[fd].owner;
3926 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003927 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003928 socklen_t lskerr = sizeof(skerr);
3929
willy tarreau05be12b2006-03-19 19:35:00 +01003930 skerr = 1;
3931 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3932 || (skerr != 0)) {
3933 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003934 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003935 fdtab[fd].state = FD_STERROR;
3936 FD_CLR(fd, StaticWriteEvent);
3937 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003938 else if (s->result != -1) {
3939 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003940 if (s->proxy->options & PR_O_HTTP_CHK) {
3941 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003942 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003943 * so we'll send the request, and won't wake the checker up now.
3944 */
3945#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003946 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003947#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003948 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003949#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003950 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003951 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3952 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3953 return 0;
3954 }
willy tarreau05be12b2006-03-19 19:35:00 +01003955 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003956 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003957 FD_CLR(fd, StaticWriteEvent);
3958 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003959 }
3960 else {
3961 /* good TCP connection is enough */
3962 s->result = 1;
3963 }
3964 }
3965
3966 task_wakeup(&rq, t);
3967 return 0;
3968}
3969
willy tarreau0f7af912005-12-17 12:21:26 +01003970
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003971/*
3972 * This function is used only for server health-checks. It handles
3973 * the server's reply to an HTTP request. It returns 1 if the server replies
3974 * 2xx or 3xx (valid responses), or -1 in other cases.
3975 */
3976int event_srv_chk_r(int fd) {
3977 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003978 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003979 struct task *t = fdtab[fd].owner;
3980 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003981 int skerr;
3982 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003983
willy tarreaua4a583a2005-12-18 01:39:19 +01003984 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003985
willy tarreau05be12b2006-03-19 19:35:00 +01003986 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3987 if (!skerr) {
3988#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003989 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003990#else
willy tarreau05be12b2006-03-19 19:35:00 +01003991 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3992 * but the connection was closed on the remote end. Fortunately, recv still
3993 * works correctly and we don't need to do the getsockopt() on linux.
3994 */
3995 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003996#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003997
3998 if ((len >= sizeof("HTTP/1.0 000")) &&
3999 !memcmp(reply, "HTTP/1.", 7) &&
4000 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
4001 result = 1;
4002 }
4003
4004 if (result == -1)
4005 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01004006
4007 if (s->result != -1)
4008 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004009
4010 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004011 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01004012 return 0;
4013}
4014
4015
4016/*
4017 * this function writes the string <str> at position <pos> which must be in buffer <b>,
4018 * and moves <end> just after the end of <str>.
4019 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
4020 * the shift value (positive or negative) is returned.
4021 * If there's no space left, the move is not done.
4022 *
4023 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004024int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01004025 int delta;
4026 int len;
4027
4028 len = strlen(str);
4029 delta = len - (end - pos);
4030
4031 if (delta + b->r >= b->data + BUFSIZE)
4032 return 0; /* no space left */
4033
4034 /* first, protect the end of the buffer */
4035 memmove(end + delta, end, b->data + b->l - end);
4036
4037 /* now, copy str over pos */
4038 memcpy(pos, str,len);
4039
willy tarreau5cbea6f2005-12-17 12:48:26 +01004040 /* we only move data after the displaced zone */
4041 if (b->r > pos) b->r += delta;
4042 if (b->w > pos) b->w += delta;
4043 if (b->h > pos) b->h += delta;
4044 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01004045 b->l += delta;
4046
4047 return delta;
4048}
4049
willy tarreau8337c6b2005-12-17 13:41:01 +01004050/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01004051 * len is 0.
4052 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004053int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01004054 int delta;
4055
4056 delta = len - (end - pos);
4057
4058 if (delta + b->r >= b->data + BUFSIZE)
4059 return 0; /* no space left */
4060
Willy TARREAUe78ae262006-01-08 01:24:12 +01004061 if (b->data + b->l < end)
4062 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
4063 return 0;
4064
willy tarreau0f7af912005-12-17 12:21:26 +01004065 /* first, protect the end of the buffer */
4066 memmove(end + delta, end, b->data + b->l - end);
4067
4068 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01004069 if (len)
4070 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01004071
willy tarreau5cbea6f2005-12-17 12:48:26 +01004072 /* we only move data after the displaced zone */
4073 if (b->r > pos) b->r += delta;
4074 if (b->w > pos) b->w += delta;
4075 if (b->h > pos) b->h += delta;
4076 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01004077 b->l += delta;
4078
4079 return delta;
4080}
4081
4082
4083int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
4084 char *old_dst = dst;
4085
4086 while (*str) {
4087 if (*str == '\\') {
4088 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01004089 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004090 int len, num;
4091
4092 num = *str - '0';
4093 str++;
4094
willy tarreau8a86dbf2005-12-18 00:45:59 +01004095 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01004096 len = matches[num].rm_eo - matches[num].rm_so;
4097 memcpy(dst, src + matches[num].rm_so, len);
4098 dst += len;
4099 }
4100
4101 }
4102 else if (*str == 'x') {
4103 unsigned char hex1, hex2;
4104 str++;
4105
willy tarreauc1f47532005-12-18 01:08:26 +01004106 hex1 = toupper(*str++) - '0';
4107 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01004108
4109 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
4110 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
4111 *dst++ = (hex1<<4) + hex2;
4112 }
4113 else
4114 *dst++ = *str++;
4115 }
4116 else
4117 *dst++ = *str++;
4118 }
4119 *dst = 0;
4120 return dst - old_dst;
4121}
4122
willy tarreauc1f47532005-12-18 01:08:26 +01004123static int ishex(char s)
4124{
4125 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
4126}
4127
4128/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
4129char *check_replace_string(char *str)
4130{
4131 char *err = NULL;
4132 while (*str) {
4133 if (*str == '\\') {
4134 err = str; /* in case of a backslash, we return the pointer to it */
4135 str++;
4136 if (!*str)
4137 return err;
4138 else if (isdigit((int)*str))
4139 err = NULL;
4140 else if (*str == 'x') {
4141 str++;
4142 if (!ishex(*str))
4143 return err;
4144 str++;
4145 if (!ishex(*str))
4146 return err;
4147 err = NULL;
4148 }
4149 else {
4150 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
4151 err = NULL;
4152 }
4153 }
4154 str++;
4155 }
4156 return err;
4157}
4158
willy tarreau0f7af912005-12-17 12:21:26 +01004159/*
4160 * manages the client FSM and its socket. BTW, it also tries to handle the
4161 * cookie. It returns 1 if a state has changed (and a resync may be needed),
4162 * 0 else.
4163 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004164int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004165 int s = t->srv_state;
4166 int c = t->cli_state;
4167 struct buffer *req = t->req;
4168 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004169 int method_checked = 0;
4170 appsess *asession_temp = NULL;
4171 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01004172
willy tarreau750a4722005-12-17 13:21:24 +01004173#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01004174 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
4175 cli_stnames[c], srv_stnames[s],
4176 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4177 t->crexpire.tv_sec, t->crexpire.tv_usec,
4178 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01004179#endif
willy tarreau0f7af912005-12-17 12:21:26 +01004180 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4181 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4182 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4183 //);
4184 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004185 /* now parse the partial (or complete) headers */
4186 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
4187 char *ptr;
4188 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01004189 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01004190
willy tarreau5cbea6f2005-12-17 12:48:26 +01004191 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01004192
willy tarreau0f7af912005-12-17 12:21:26 +01004193 /* look for the end of the current header */
4194 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
4195 ptr++;
4196
willy tarreau5cbea6f2005-12-17 12:48:26 +01004197 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004198 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02004199
4200 /*
4201 * first, let's check that it's not a leading empty line, in
4202 * which case we'll ignore and remove it (according to RFC2616).
4203 */
4204 if (req->h == req->data) {
4205 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4206 if (ptr > req->r - 2) {
4207 /* this is a partial header, let's wait for more to come */
4208 req->lr = ptr;
4209 break;
4210 }
4211
4212 /* now we know that *ptr is either \r or \n,
4213 * and that there are at least 1 char after it.
4214 */
4215 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4216 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4217 else
4218 req->lr = ptr + 2; /* \r\n or \n\r */
4219 /* ignore empty leading lines */
4220 buffer_replace2(req, req->h, req->lr, NULL, 0);
4221 req->h = req->lr;
4222 continue;
4223 }
4224
willy tarreau5cbea6f2005-12-17 12:48:26 +01004225 /* we can only get here after an end of headers */
4226 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01004227
willy tarreaue39cd132005-12-17 13:00:18 +01004228 if (t->flags & SN_CLDENY) {
4229 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01004230 t->logs.status = 403;
willy tarreau47ee7ad2006-05-18 01:25:36 +02004231 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now); /* let's log the request time */
willy tarreau8337c6b2005-12-17 13:41:01 +01004232 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01004233 if (!(t->flags & SN_ERR_MASK))
4234 t->flags |= SN_ERR_PRXCOND;
4235 if (!(t->flags & SN_FINST_MASK))
4236 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004237 return 1;
4238 }
4239
willy tarreau9e138862006-05-14 23:06:28 +02004240 /* Right now, we know that we have processed the entire headers
4241 * and that unwanted requests have been filtered out. We can do
4242 * whatever we want.
4243 */
4244
willy tarreau9e138862006-05-14 23:06:28 +02004245 if (t->proxy->uri_auth != NULL
4246 && t->req_line.len >= t->proxy->uri_auth->uri_len + 4) { /* +4 for "GET /" */
4247 if (!memcmp(t->req_line.str + 4,
4248 t->proxy->uri_auth->uri_prefix, t->proxy->uri_auth->uri_len)
4249 && !memcmp(t->req_line.str, "GET ", 4)) {
4250 struct user_auth *user;
4251 int authenticated;
4252
4253 /* we are in front of a interceptable URI. Let's check
4254 * if there's an authentication and if it's valid.
4255 */
4256 user = t->proxy->uri_auth->users;
4257 if (!user) {
4258 /* no user auth required, it's OK */
4259 authenticated = 1;
4260 } else {
4261 authenticated = 0;
4262
4263 /* a user list is defined, we have to check.
4264 * skip 21 chars for "Authorization: Basic ".
4265 */
4266 if (t->auth_hdr.len < 21 || memcmp(t->auth_hdr.str + 14, " Basic ", 7))
4267 user = NULL;
4268
4269 while (user) {
4270 if ((t->auth_hdr.len == user->user_len + 21)
4271 && !memcmp(t->auth_hdr.str+21, user->user_pwd, user->user_len)) {
4272 authenticated = 1;
4273 break;
4274 }
4275 user = user->next;
willy tarreau9e138862006-05-14 23:06:28 +02004276 }
4277 }
4278
4279 if (!authenticated) {
4280 int msglen;
4281
4282 /* no need to go further */
4283
4284 msglen = sprintf(trash, HTTP_401_fmt, t->proxy->uri_auth->auth_realm);
4285 t->logs.status = 401;
4286 client_retnclose(t, msglen, trash);
4287 if (!(t->flags & SN_ERR_MASK))
4288 t->flags |= SN_ERR_PRXCOND;
4289 if (!(t->flags & SN_FINST_MASK))
4290 t->flags |= SN_FINST_R;
4291 return 1;
4292 }
4293
willy tarreaue0331262006-05-15 03:02:46 +02004294 t->cli_state = CL_STSHUTR;
willy tarreau950609c2006-05-18 01:23:51 +02004295 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
4296 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreaue0331262006-05-15 03:02:46 +02004297 t->data_source = DATA_SRC_STATS;
willy tarreau1f431b52006-05-21 14:46:15 +02004298 t->data_state = DATA_ST_INIT;
willy tarreaue0331262006-05-15 03:02:46 +02004299 produce_content(t);
4300 return 1;
willy tarreau9e138862006-05-14 23:06:28 +02004301 }
4302 }
4303
4304
willy tarreau5cbea6f2005-12-17 12:48:26 +01004305 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004306 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
4307 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004308 }
willy tarreau0f7af912005-12-17 12:21:26 +01004309
willy tarreau9fe663a2005-12-17 13:02:59 +01004310 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01004311 if (t->cli_addr.ss_family == AF_INET) {
4312 unsigned char *pn;
4313 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
4314 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
4315 pn[0], pn[1], pn[2], pn[3]);
4316 buffer_replace2(req, req->h, req->h, trash, len);
4317 }
4318 else if (t->cli_addr.ss_family == AF_INET6) {
4319 char pn[INET6_ADDRSTRLEN];
4320 inet_ntop(AF_INET6,
4321 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
4322 pn, sizeof(pn));
4323 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
4324 buffer_replace2(req, req->h, req->h, trash, len);
4325 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004326 }
4327
willy tarreau25c4ea52005-12-18 00:49:49 +01004328 /* add a "connection: close" line if needed */
4329 if (t->proxy->options & PR_O_HTTP_CLOSE)
4330 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
4331
willy tarreau982249e2005-12-18 00:57:06 +01004332 if (!memcmp(req->data, "POST ", 5)) {
4333 /* this is a POST request, which is not cacheable by default */
4334 t->flags |= SN_POST;
4335 }
willy tarreaucd878942005-12-17 13:27:43 +01004336
willy tarreau5cbea6f2005-12-17 12:48:26 +01004337 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004338 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01004339
willy tarreau750a4722005-12-17 13:21:24 +01004340 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004341 /* FIXME: we'll set the client in a wait state while we try to
4342 * connect to the server. Is this really needed ? wouldn't it be
willy tarreau0889c962006-04-24 14:36:48 +02004343 * better to release the maximum of system buffers instead ?
4344 * The solution is to enable the FD but set its time-out to
4345 * eternity as long as the server-side does not enable data xfer.
4346 * CL_STDATA also has to take care of this, which is done below.
4347 */
willy tarreauef900ab2005-12-17 12:52:52 +01004348 //FD_CLR(t->cli_fd, StaticReadEvent);
4349 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01004350
4351 /* FIXME: if we break here (as up to 1.1.23), having the client
4352 * shutdown its connection can lead to an abort further.
4353 * it's better to either return 1 or even jump directly to the
4354 * data state which will save one schedule.
4355 */
4356 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01004357
4358 if (!t->proxy->clitimeout ||
4359 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4360 /* If the client has no timeout, or if the server is not ready yet,
4361 * and we know for sure that it can expire, then it's cleaner to
4362 * disable the timeout on the client side so that too low values
4363 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01004364 *
4365 * FIXME-20050705: the server needs a way to re-enable this time-out
4366 * when it switches its state, otherwise a client can stay connected
4367 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01004368 */
4369 tv_eternity(&t->crexpire);
4370
willy tarreau197e8ec2005-12-17 14:10:59 +01004371 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004372 }
willy tarreau0f7af912005-12-17 12:21:26 +01004373
Willy TARREAU13032e72006-03-12 17:31:45 +01004374 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4375 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004376 /* this is a partial header, let's wait for more to come */
4377 req->lr = ptr;
4378 break;
4379 }
willy tarreau0f7af912005-12-17 12:21:26 +01004380
willy tarreau5cbea6f2005-12-17 12:48:26 +01004381 /* now we know that *ptr is either \r or \n,
4382 * and that there are at least 1 char after it.
4383 */
4384 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4385 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4386 else
4387 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01004388
willy tarreau5cbea6f2005-12-17 12:48:26 +01004389 /*
4390 * now we know that we have a full header ; we can do whatever
4391 * we want with these pointers :
4392 * req->h = beginning of header
4393 * ptr = end of header (first \r or \n)
4394 * req->lr = beginning of next line (next rep->h)
4395 * req->r = end of data (not used at this stage)
4396 */
willy tarreau0f7af912005-12-17 12:21:26 +01004397
willy tarreau12350152005-12-18 01:03:27 +01004398 if (!method_checked && (t->proxy->appsession_name != NULL) &&
4399 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
4400 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
4401
4402 /* skip ; */
4403 request_line++;
4404
4405 /* look if we have a jsessionid */
4406
4407 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
4408
4409 /* skip jsessionid= */
4410 request_line += t->proxy->appsession_name_len + 1;
4411
4412 /* First try if we allready have an appsession */
4413 asession_temp = &local_asession;
4414
4415 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4416 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
4417 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
4418 return 0;
4419 }
4420
4421 /* Copy the sessionid */
4422 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
4423 asession_temp->sessid[t->proxy->appsession_len] = 0;
4424 asession_temp->serverid = NULL;
4425
4426 /* only do insert, if lookup fails */
4427 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
4428 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4429 Alert("Not enough memory process_cli():asession:calloc().\n");
4430 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4431 return 0;
4432 }
4433 asession_temp->sessid = local_asession.sessid;
4434 asession_temp->serverid = local_asession.serverid;
4435 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004436 } /* end if (chtbl_lookup()) */
4437 else {
willy tarreau12350152005-12-18 01:03:27 +01004438 /*free wasted memory;*/
4439 pool_free_to(apools.sessid, local_asession.sessid);
4440 }
4441
4442 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4443 asession_temp->request_count++;
4444
4445#if defined(DEBUG_HASH)
4446 print_table(&(t->proxy->htbl_proxy));
4447#endif
4448
4449 if (asession_temp->serverid == NULL) {
4450 Alert("Found Application Session without matching server.\n");
4451 } else {
4452 struct server *srv = t->proxy->srv;
4453 while (srv) {
4454 if (strcmp(srv->id, asession_temp->serverid) == 0) {
4455 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4456 /* we found the server and it's usable */
4457 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004458 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004459 t->srv = srv;
4460 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01004461 } else {
willy tarreau12350152005-12-18 01:03:27 +01004462 t->flags &= ~SN_CK_MASK;
4463 t->flags |= SN_CK_DOWN;
4464 }
willy tarreaub952e1d2005-12-18 01:31:20 +01004465 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01004466 srv = srv->next;
4467 }/* end while(srv) */
4468 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01004469 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01004470 else {
4471 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
4472 }
willy tarreau598da412005-12-18 01:07:29 +01004473 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01004474 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01004475 else{
4476 //printf("No Methode-Header with Session-String\n");
4477 }
4478
willy tarreau8337c6b2005-12-17 13:41:01 +01004479 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004480 /* we have a complete HTTP request that we must log */
4481 int urilen;
4482
willy tarreaua1598082005-12-17 13:08:06 +01004483 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004484 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01004485 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01004486 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01004487 if (!(t->flags & SN_ERR_MASK))
4488 t->flags |= SN_ERR_PRXCOND;
4489 if (!(t->flags & SN_FINST_MASK))
4490 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01004491 return 1;
4492 }
4493
4494 urilen = ptr - req->h;
4495 if (urilen >= REQURI_LEN)
4496 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01004497 memcpy(t->logs.uri, req->h, urilen);
4498 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004499
willy tarreaua1598082005-12-17 13:08:06 +01004500 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01004501 sess_log(t);
4502 }
willy tarreau4302f492005-12-18 01:00:37 +01004503 else if (t->logs.logwait & LW_REQHDR) {
4504 struct cap_hdr *h;
4505 int len;
4506 for (h = t->proxy->req_cap; h; h = h->next) {
4507 if ((h->namelen + 2 <= ptr - req->h) &&
4508 (req->h[h->namelen] == ':') &&
4509 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
4510
4511 if (t->req_cap[h->index] == NULL)
4512 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4513
4514 len = ptr - (req->h + h->namelen + 2);
4515 if (len > h->len)
4516 len = h->len;
4517
4518 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
4519 t->req_cap[h->index][len]=0;
4520 }
4521 }
4522
4523 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004524
willy tarreau5cbea6f2005-12-17 12:48:26 +01004525 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004526
willy tarreau982249e2005-12-18 00:57:06 +01004527 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004528 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004529 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 +01004530 max = ptr - req->h;
4531 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004532 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004533 trash[len++] = '\n';
4534 write(1, trash, len);
4535 }
willy tarreau0f7af912005-12-17 12:21:26 +01004536
willy tarreau25c4ea52005-12-18 00:49:49 +01004537
4538 /* remove "connection: " if needed */
4539 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4540 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
4541 delete_header = 1;
4542 }
4543
willy tarreau5cbea6f2005-12-17 12:48:26 +01004544 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004545 if (!delete_header && t->proxy->req_exp != NULL
4546 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004547 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004548 char term;
4549
4550 term = *ptr;
4551 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004552 exp = t->proxy->req_exp;
4553 do {
4554 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
4555 switch (exp->action) {
4556 case ACT_ALLOW:
4557 if (!(t->flags & SN_CLDENY))
4558 t->flags |= SN_CLALLOW;
4559 break;
4560 case ACT_REPLACE:
4561 if (!(t->flags & SN_CLDENY)) {
4562 int len = exp_replace(trash, req->h, exp->replace, pmatch);
4563 ptr += buffer_replace2(req, req->h, ptr, trash, len);
4564 }
4565 break;
4566 case ACT_REMOVE:
4567 if (!(t->flags & SN_CLDENY))
4568 delete_header = 1;
4569 break;
4570 case ACT_DENY:
4571 if (!(t->flags & SN_CLALLOW))
4572 t->flags |= SN_CLDENY;
4573 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004574 case ACT_PASS: /* we simply don't deny this one */
4575 break;
willy tarreau0f7af912005-12-17 12:21:26 +01004576 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004577 break;
willy tarreau0f7af912005-12-17 12:21:26 +01004578 }
willy tarreaue39cd132005-12-17 13:00:18 +01004579 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004580 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01004581 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004582
willy tarreau240afa62005-12-17 13:14:35 +01004583 /* Now look for cookies. Conforming to RFC2109, we have to support
4584 * attributes whose name begin with a '$', and associate them with
4585 * the right cookie, if we want to delete this cookie.
4586 * So there are 3 cases for each cookie read :
4587 * 1) it's a special attribute, beginning with a '$' : ignore it.
4588 * 2) it's a server id cookie that we *MAY* want to delete : save
4589 * some pointers on it (last semi-colon, beginning of cookie...)
4590 * 3) it's an application cookie : we *MAY* have to delete a previous
4591 * "special" cookie.
4592 * At the end of loop, if a "special" cookie remains, we may have to
4593 * remove it. If no application cookie persists in the header, we
4594 * *MUST* delete it
4595 */
willy tarreau12350152005-12-18 01:03:27 +01004596 if (!delete_header &&
4597 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01004598 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01004599 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004600 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01004601 char *del_colon, *del_cookie, *colon;
4602 int app_cookies;
4603
willy tarreau5cbea6f2005-12-17 12:48:26 +01004604 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01004605 colon = p1;
4606 /* del_cookie == NULL => nothing to be deleted */
4607 del_colon = del_cookie = NULL;
4608 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004609
4610 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01004611 /* skip spaces and colons, but keep an eye on these ones */
4612 while (p1 < ptr) {
4613 if (*p1 == ';' || *p1 == ',')
4614 colon = p1;
4615 else if (!isspace((int)*p1))
4616 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004617 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01004618 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004619
4620 if (p1 == ptr)
4621 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004622
4623 /* p1 is at the beginning of the cookie name */
4624 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01004625 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004626 p2++;
4627
4628 if (p2 == ptr)
4629 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004630
4631 p3 = p2 + 1; /* skips the '=' sign */
4632 if (p3 == ptr)
4633 break;
4634
willy tarreau240afa62005-12-17 13:14:35 +01004635 p4 = p3;
4636 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004637 p4++;
4638
4639 /* here, we have the cookie name between p1 and p2,
4640 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01004641 * we can process it :
4642 *
4643 * Cookie: NAME=VALUE;
4644 * | || || |
4645 * | || || +--> p4
4646 * | || |+-------> p3
4647 * | || +--------> p2
4648 * | |+------------> p1
4649 * | +-------------> colon
4650 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01004651 */
4652
willy tarreau240afa62005-12-17 13:14:35 +01004653 if (*p1 == '$') {
4654 /* skip this one */
4655 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004656 else {
4657 /* first, let's see if we want to capture it */
4658 if (t->proxy->capture_name != NULL &&
4659 t->logs.cli_cookie == NULL &&
4660 (p4 - p1 >= t->proxy->capture_namelen) &&
4661 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4662 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004663
willy tarreau8337c6b2005-12-17 13:41:01 +01004664 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4665 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01004666 } else {
4667 if (log_len > t->proxy->capture_len)
4668 log_len = t->proxy->capture_len;
4669 memcpy(t->logs.cli_cookie, p1, log_len);
4670 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01004671 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004672 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004673
4674 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4675 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
4676 /* Cool... it's the right one */
4677 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01004678 char *delim;
4679
4680 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4681 * have the server ID betweek p3 and delim, and the original cookie between
4682 * delim+1 and p4. Otherwise, delim==p4 :
4683 *
4684 * Cookie: NAME=SRV~VALUE;
4685 * | || || | |
4686 * | || || | +--> p4
4687 * | || || +--------> delim
4688 * | || |+-----------> p3
4689 * | || +------------> p2
4690 * | |+----------------> p1
4691 * | +-----------------> colon
4692 * +------------------------> req->h
4693 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004694
willy tarreau0174f312005-12-18 01:02:42 +01004695 if (t->proxy->options & PR_O_COOK_PFX) {
4696 for (delim = p3; delim < p4; delim++)
4697 if (*delim == COOKIE_DELIM)
4698 break;
4699 }
4700 else
4701 delim = p4;
4702
4703
4704 /* Here, we'll look for the first running server which supports the cookie.
4705 * This allows to share a same cookie between several servers, for example
4706 * to dedicate backup servers to specific servers only.
willy tarreau422bb2e2006-05-10 04:27:21 +02004707 * However, to prevent clients from sticking to cookie-less backup server
4708 * when they have incidentely learned an empty cookie, we simply ignore
4709 * empty cookies and mark them as invalid.
willy tarreau0174f312005-12-18 01:02:42 +01004710 */
willy tarreau422bb2e2006-05-10 04:27:21 +02004711 if (delim == p3)
4712 srv = NULL;
4713
willy tarreau0174f312005-12-18 01:02:42 +01004714 while (srv) {
4715 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
4716 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4717 /* we found the server and it's usable */
4718 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004719 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau0174f312005-12-18 01:02:42 +01004720 t->srv = srv;
4721 break;
willy tarreau12350152005-12-18 01:03:27 +01004722 } else {
willy tarreau0174f312005-12-18 01:02:42 +01004723 /* we found a server, but it's down */
4724 t->flags &= ~SN_CK_MASK;
4725 t->flags |= SN_CK_DOWN;
4726 }
4727 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004728 srv = srv->next;
4729 }
4730
willy tarreau0174f312005-12-18 01:02:42 +01004731 if (!srv && !(t->flags & SN_CK_DOWN)) {
4732 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01004733 t->flags &= ~SN_CK_MASK;
4734 t->flags |= SN_CK_INVALID;
4735 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004736
willy tarreau0174f312005-12-18 01:02:42 +01004737 /* depending on the cookie mode, we may have to either :
4738 * - delete the complete cookie if we're in insert+indirect mode, so that
4739 * the server never sees it ;
4740 * - remove the server id from the cookie value, and tag the cookie as an
4741 * application cookie so that it does not get accidentely removed later,
4742 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01004743 */
willy tarreau0174f312005-12-18 01:02:42 +01004744 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
4745 buffer_replace2(req, p3, delim + 1, NULL, 0);
4746 p4 -= (delim + 1 - p3);
4747 ptr -= (delim + 1 - p3);
4748 del_cookie = del_colon = NULL;
4749 app_cookies++; /* protect the header from deletion */
4750 }
4751 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01004752 (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 +01004753 del_cookie = p1;
4754 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01004755 }
willy tarreau12350152005-12-18 01:03:27 +01004756 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01004757 /* now we know that we must keep this cookie since it's
4758 * not ours. But if we wanted to delete our cookie
4759 * earlier, we cannot remove the complete header, but we
4760 * can remove the previous block itself.
4761 */
4762 app_cookies++;
4763
4764 if (del_cookie != NULL) {
4765 buffer_replace2(req, del_cookie, p1, NULL, 0);
4766 p4 -= (p1 - del_cookie);
4767 ptr -= (p1 - del_cookie);
4768 del_cookie = del_colon = NULL;
4769 }
willy tarreau240afa62005-12-17 13:14:35 +01004770 }
willy tarreau12350152005-12-18 01:03:27 +01004771
4772 if ((t->proxy->appsession_name != NULL) &&
4773 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4774 /* first, let's see if the cookie is our appcookie*/
4775
4776 /* Cool... it's the right one */
4777
4778 asession_temp = &local_asession;
4779
4780 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4781 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4782 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4783 return 0;
4784 }
4785
4786 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4787 asession_temp->sessid[t->proxy->appsession_len] = 0;
4788 asession_temp->serverid = NULL;
4789
4790 /* only do insert, if lookup fails */
4791 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4792 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4793 Alert("Not enough memory process_cli():asession:calloc().\n");
4794 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4795 return 0;
4796 }
4797
4798 asession_temp->sessid = local_asession.sessid;
4799 asession_temp->serverid = local_asession.serverid;
4800 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4801 }
4802 else{
4803 /* free wasted memory */
4804 pool_free_to(apools.sessid, local_asession.sessid);
4805 }
4806
4807 if (asession_temp->serverid == NULL) {
4808 Alert("Found Application Session without matching server.\n");
4809 } else {
4810 struct server *srv = t->proxy->srv;
4811 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01004812 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01004813 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4814 /* we found the server and it's usable */
4815 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004816 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004817 t->srv = srv;
4818 break;
4819 } else {
4820 t->flags &= ~SN_CK_MASK;
4821 t->flags |= SN_CK_DOWN;
4822 }
4823 }
4824 srv = srv->next;
4825 }/* end while(srv) */
4826 }/* end else if server == NULL */
4827
4828 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01004829 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004830 }
willy tarreau240afa62005-12-17 13:14:35 +01004831
willy tarreau5cbea6f2005-12-17 12:48:26 +01004832 /* we'll have to look for another cookie ... */
4833 p1 = p4;
4834 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01004835
4836 /* There's no more cookie on this line.
4837 * We may have marked the last one(s) for deletion.
4838 * We must do this now in two ways :
4839 * - if there is no app cookie, we simply delete the header ;
4840 * - if there are app cookies, we must delete the end of the
4841 * string properly, including the colon/semi-colon before
4842 * the cookie name.
4843 */
4844 if (del_cookie != NULL) {
4845 if (app_cookies) {
4846 buffer_replace2(req, del_colon, ptr, NULL, 0);
4847 /* WARNING! <ptr> becomes invalid for now. If some code
4848 * below needs to rely on it before the end of the global
4849 * header loop, we need to correct it with this code :
willy tarreau240afa62005-12-17 13:14:35 +01004850 */
willy tarreau9e138862006-05-14 23:06:28 +02004851 ptr = del_colon;
willy tarreau240afa62005-12-17 13:14:35 +01004852 }
4853 else
4854 delete_header = 1;
4855 }
4856 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004857
4858 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004859 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01004860 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau9e138862006-05-14 23:06:28 +02004861 /* WARNING: ptr is not valid anymore, since the header may have
4862 * been deleted or truncated ! */
4863 } else {
4864 /* try to catch the first line as the request */
4865 if (t->req_line.len < 0) {
4866 t->req_line.str = req->h;
4867 t->req_line.len = ptr - req->h;
4868 }
4869
4870 /* We might also need the 'Authorization: ' header */
4871 if (t->auth_hdr.len < 0 &&
4872 t->proxy->uri_auth != NULL &&
4873 ptr > req->h + 15 &&
4874 !strncasecmp("Authorization: ", req->h, 15)) {
4875 t->auth_hdr.str = req->h;
4876 t->auth_hdr.len = ptr - req->h;
4877 }
willy tarreau0f7af912005-12-17 12:21:26 +01004878 }
willy tarreau240afa62005-12-17 13:14:35 +01004879
willy tarreau5cbea6f2005-12-17 12:48:26 +01004880 req->h = req->lr;
4881 } /* while (req->lr < req->r) */
4882
4883 /* end of header processing (even if incomplete) */
4884
willy tarreauef900ab2005-12-17 12:52:52 +01004885 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4886 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4887 * full. We cannot loop here since event_cli_read will disable it only if
4888 * req->l == rlim-data
4889 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004890 FD_SET(t->cli_fd, StaticReadEvent);
4891 if (t->proxy->clitimeout)
4892 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4893 else
4894 tv_eternity(&t->crexpire);
4895 }
4896
willy tarreaue39cd132005-12-17 13:00:18 +01004897 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01004898 * won't be able to free more later, so the session will never terminate.
4899 */
willy tarreaue39cd132005-12-17 13:00:18 +01004900 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01004901 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01004902 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01004903 if (!(t->flags & SN_ERR_MASK))
4904 t->flags |= SN_ERR_PRXCOND;
4905 if (!(t->flags & SN_FINST_MASK))
4906 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004907 return 1;
4908 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004909 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004910 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004911 tv_eternity(&t->crexpire);
4912 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004913 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004914 if (!(t->flags & SN_ERR_MASK))
4915 t->flags |= SN_ERR_CLICL;
4916 if (!(t->flags & SN_FINST_MASK))
4917 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004918 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004919 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004920 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4921
4922 /* read timeout : give up with an error message.
4923 */
4924 t->logs.status = 408;
4925 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004926 if (!(t->flags & SN_ERR_MASK))
4927 t->flags |= SN_ERR_CLITO;
4928 if (!(t->flags & SN_FINST_MASK))
4929 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004930 return 1;
4931 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004932
4933 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004934 }
4935 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004936 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004937 /* FIXME: this error handling is partly buggy because we always report
4938 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4939 * or HEADER phase. BTW, it's not logical to expire the client while
4940 * we're waiting for the server to connect.
4941 */
willy tarreau0f7af912005-12-17 12:21:26 +01004942 /* read or write error */
4943 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004944 tv_eternity(&t->crexpire);
4945 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004946 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004947 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004948 if (!(t->flags & SN_ERR_MASK))
4949 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004950 if (!(t->flags & SN_FINST_MASK)) {
4951 if (t->pend_pos)
4952 t->flags |= SN_FINST_Q;
4953 else if (s == SV_STCONN)
4954 t->flags |= SN_FINST_C;
4955 else
4956 t->flags |= SN_FINST_D;
4957 }
willy tarreau0f7af912005-12-17 12:21:26 +01004958 return 1;
4959 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004960 /* last read, or end of server write */
4961 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004962 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004963 tv_eternity(&t->crexpire);
4964 shutdown(t->cli_fd, SHUT_RD);
4965 t->cli_state = CL_STSHUTR;
4966 return 1;
4967 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004968 /* last server read and buffer empty */
4969 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004970 FD_CLR(t->cli_fd, StaticWriteEvent);
4971 tv_eternity(&t->cwexpire);
4972 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004973 /* We must ensure that the read part is still alive when switching
4974 * to shutw */
4975 FD_SET(t->cli_fd, StaticReadEvent);
4976 if (t->proxy->clitimeout)
4977 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004978 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004979 //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 +01004980 return 1;
4981 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004982 /* read timeout */
4983 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4984 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004985 tv_eternity(&t->crexpire);
4986 shutdown(t->cli_fd, SHUT_RD);
4987 t->cli_state = CL_STSHUTR;
4988 if (!(t->flags & SN_ERR_MASK))
4989 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004990 if (!(t->flags & SN_FINST_MASK)) {
4991 if (t->pend_pos)
4992 t->flags |= SN_FINST_Q;
4993 else if (s == SV_STCONN)
4994 t->flags |= SN_FINST_C;
4995 else
4996 t->flags |= SN_FINST_D;
4997 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004998 return 1;
4999 }
5000 /* write timeout */
5001 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
5002 FD_CLR(t->cli_fd, StaticWriteEvent);
5003 tv_eternity(&t->cwexpire);
5004 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005005 /* We must ensure that the read part is still alive when switching
5006 * to shutw */
5007 FD_SET(t->cli_fd, StaticReadEvent);
5008 if (t->proxy->clitimeout)
5009 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
5010
willy tarreau036e1ce2005-12-17 13:46:33 +01005011 t->cli_state = CL_STSHUTW;
5012 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01005013 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005014 if (!(t->flags & SN_FINST_MASK)) {
5015 if (t->pend_pos)
5016 t->flags |= SN_FINST_Q;
5017 else if (s == SV_STCONN)
5018 t->flags |= SN_FINST_C;
5019 else
5020 t->flags |= SN_FINST_D;
5021 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005022 return 1;
5023 }
willy tarreau0f7af912005-12-17 12:21:26 +01005024
willy tarreauc58fc692005-12-17 14:13:08 +01005025 if (req->l >= req->rlim - req->data) {
5026 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01005027 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01005028 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01005029 FD_CLR(t->cli_fd, StaticReadEvent);
5030 tv_eternity(&t->crexpire);
5031 }
5032 }
5033 else {
willy tarreauef900ab2005-12-17 12:52:52 +01005034 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01005035 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
5036 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01005037 if (!t->proxy->clitimeout ||
5038 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
5039 /* If the client has no timeout, or if the server not ready yet, and we
5040 * know for sure that it can expire, then it's cleaner to disable the
5041 * timeout on the client side so that too low values cannot make the
5042 * sessions abort too early.
5043 */
willy tarreau0f7af912005-12-17 12:21:26 +01005044 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01005045 else
5046 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005047 }
5048 }
5049
5050 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01005051 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005052 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5053 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
5054 tv_eternity(&t->cwexpire);
5055 }
5056 }
5057 else { /* buffer not empty */
5058 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5059 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005060 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005061 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005062 /* FIXME: to prevent the client from expiring read timeouts during writes,
5063 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005064 t->crexpire = t->cwexpire;
5065 }
willy tarreau0f7af912005-12-17 12:21:26 +01005066 else
5067 tv_eternity(&t->cwexpire);
5068 }
5069 }
5070 return 0; /* other cases change nothing */
5071 }
5072 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005073 if (t->res_cw == RES_ERROR) {
5074 tv_eternity(&t->cwexpire);
5075 fd_delete(t->cli_fd);
5076 t->cli_state = CL_STCLOSE;
5077 if (!(t->flags & SN_ERR_MASK))
5078 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02005079 if (!(t->flags & SN_FINST_MASK)) {
5080 if (t->pend_pos)
5081 t->flags |= SN_FINST_Q;
5082 else if (s == SV_STCONN)
5083 t->flags |= SN_FINST_C;
5084 else
5085 t->flags |= SN_FINST_D;
5086 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005087 return 1;
5088 }
willy tarreaue0331262006-05-15 03:02:46 +02005089 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
5090 && !(t->flags & SN_SELF_GEN)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005091 tv_eternity(&t->cwexpire);
5092 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005093 t->cli_state = CL_STCLOSE;
5094 return 1;
5095 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005096 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
5097 tv_eternity(&t->cwexpire);
5098 fd_delete(t->cli_fd);
5099 t->cli_state = CL_STCLOSE;
5100 if (!(t->flags & SN_ERR_MASK))
5101 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005102 if (!(t->flags & SN_FINST_MASK)) {
5103 if (t->pend_pos)
5104 t->flags |= SN_FINST_Q;
5105 else if (s == SV_STCONN)
5106 t->flags |= SN_FINST_C;
5107 else
5108 t->flags |= SN_FINST_D;
5109 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005110 return 1;
5111 }
willy tarreaue0331262006-05-15 03:02:46 +02005112
5113 if (t->flags & SN_SELF_GEN) {
5114 produce_content(t);
5115 if (rep->l == 0) {
5116 tv_eternity(&t->cwexpire);
5117 fd_delete(t->cli_fd);
5118 t->cli_state = CL_STCLOSE;
5119 return 1;
5120 }
5121 }
5122
5123 if ((rep->l == 0)
5124 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005125 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5126 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
5127 tv_eternity(&t->cwexpire);
5128 }
5129 }
5130 else { /* buffer not empty */
5131 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5132 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005133 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005134 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005135 /* FIXME: to prevent the client from expiring read timeouts during writes,
5136 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005137 t->crexpire = t->cwexpire;
5138 }
willy tarreau0f7af912005-12-17 12:21:26 +01005139 else
5140 tv_eternity(&t->cwexpire);
5141 }
5142 }
5143 return 0;
5144 }
5145 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005146 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005147 tv_eternity(&t->crexpire);
5148 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005149 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005150 if (!(t->flags & SN_ERR_MASK))
5151 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02005152 if (!(t->flags & SN_FINST_MASK)) {
5153 if (t->pend_pos)
5154 t->flags |= SN_FINST_Q;
5155 else if (s == SV_STCONN)
5156 t->flags |= SN_FINST_C;
5157 else
5158 t->flags |= SN_FINST_D;
5159 }
willy tarreau0f7af912005-12-17 12:21:26 +01005160 return 1;
5161 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005162 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
5163 tv_eternity(&t->crexpire);
5164 fd_delete(t->cli_fd);
5165 t->cli_state = CL_STCLOSE;
5166 return 1;
5167 }
5168 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
5169 tv_eternity(&t->crexpire);
5170 fd_delete(t->cli_fd);
5171 t->cli_state = CL_STCLOSE;
5172 if (!(t->flags & SN_ERR_MASK))
5173 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005174 if (!(t->flags & SN_FINST_MASK)) {
5175 if (t->pend_pos)
5176 t->flags |= SN_FINST_Q;
5177 else if (s == SV_STCONN)
5178 t->flags |= SN_FINST_C;
5179 else
5180 t->flags |= SN_FINST_D;
5181 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005182 return 1;
5183 }
willy tarreauef900ab2005-12-17 12:52:52 +01005184 else if (req->l >= req->rlim - req->data) {
5185 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01005186
5187 /* FIXME-20050705: is it possible for a client to maintain a session
5188 * after the timeout by sending more data after it receives a close ?
5189 */
5190
willy tarreau0f7af912005-12-17 12:21:26 +01005191 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01005192 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01005193 FD_CLR(t->cli_fd, StaticReadEvent);
5194 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01005195 //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 +01005196 }
5197 }
5198 else {
willy tarreauef900ab2005-12-17 12:52:52 +01005199 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01005200 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
5201 FD_SET(t->cli_fd, StaticReadEvent);
5202 if (t->proxy->clitimeout)
5203 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
5204 else
5205 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01005206 //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 +01005207 }
5208 }
5209 return 0;
5210 }
5211 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005212 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005213 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005214 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 +01005215 write(1, trash, len);
5216 }
5217 return 0;
5218 }
5219 return 0;
5220}
5221
willy tarreaudfece232006-05-02 00:19:57 +02005222/* This function turns the server state into the SV_STCLOSE, and sets
5223 * indicators accordingly. Note that if <status> is 0, no message is
5224 * returned.
5225 */
5226void srv_close_with_err(struct session *t, int err, int finst, int status, int msglen, char *msg) {
5227 t->srv_state = SV_STCLOSE;
5228 if (status > 0) {
5229 t->logs.status = status;
5230 if (t->proxy->mode == PR_MODE_HTTP)
5231 client_return(t, msglen, msg);
5232 }
5233 if (!(t->flags & SN_ERR_MASK))
5234 t->flags |= err;
5235 if (!(t->flags & SN_FINST_MASK))
5236 t->flags |= finst;
5237}
5238
5239/*
5240 * This function checks the retry count during the connect() job.
5241 * It updates the session's srv_state and retries, so that the caller knows
5242 * what it has to do. It uses the last connection error to set the log when
5243 * it expires. It returns 1 when it has expired, and 0 otherwise.
5244 */
5245int srv_count_retry_down(struct session *t, int conn_err) {
5246 /* we are in front of a retryable error */
5247 t->conn_retries--;
5248 if (t->conn_retries < 0) {
5249 /* if not retryable anymore, let's abort */
5250 tv_eternity(&t->cnexpire);
5251 srv_close_with_err(t, conn_err, SN_FINST_C,
5252 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaue3b30652006-05-21 16:23:22 +02005253 if (t->srv)
5254 t->srv->failed_conns++;
5255 t->proxy->failed_conns++;
5256
willy tarreaudfece232006-05-02 00:19:57 +02005257 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005258 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005259 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005260 if (may_dequeue_tasks(t->srv, t->proxy))
5261 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005262 return 1;
5263 }
5264 return 0;
5265}
willy tarreau0f7af912005-12-17 12:21:26 +01005266
5267/*
willy tarreaudfece232006-05-02 00:19:57 +02005268 * This function performs the retryable part of the connect() job.
5269 * It updates the session's srv_state and retries, so that the caller knows
5270 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
5271 * it needs to redispatch.
5272 */
5273int srv_retryable_connect(struct session *t) {
5274 int conn_err;
5275
5276 /* This loop ensures that we stop before the last retry in case of a
5277 * redispatchable server.
5278 */
5279 do {
5280 /* initiate a connection to the server */
5281 conn_err = connect_server(t);
5282 switch (conn_err) {
5283
5284 case SN_ERR_NONE:
5285 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
5286 t->srv_state = SV_STCONN;
5287 return 1;
5288
5289 case SN_ERR_INTERNAL:
5290 tv_eternity(&t->cnexpire);
5291 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
5292 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreaue3b30652006-05-21 16:23:22 +02005293 if (t->srv)
5294 t->srv->failed_conns++;
5295 t->proxy->failed_conns++;
willy tarreaudfece232006-05-02 00:19:57 +02005296 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02005297 if (may_dequeue_tasks(t->srv, t->proxy))
5298 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005299 return 1;
5300 }
5301 /* ensure that we have enough retries left */
willy tarreau59a6cc22006-05-12 01:29:08 +02005302 if (srv_count_retry_down(t, conn_err)) {
5303 /* let's try to offer this slot to anybody */
5304 if (may_dequeue_tasks(t->srv, t->proxy))
5305 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005306 return 1;
willy tarreau59a6cc22006-05-12 01:29:08 +02005307 }
willy tarreaudfece232006-05-02 00:19:57 +02005308 } while (t->srv == NULL || t->conn_retries > 0 || !(t->proxy->options & PR_O_REDISP));
5309
5310 /* We're on our last chance, and the REDISP option was specified.
5311 * We will ignore cookie and force to balance or use the dispatcher.
5312 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005313 /* let's try to offer this slot to anybody */
5314 if (may_dequeue_tasks(t->srv, t->proxy))
5315 task_wakeup(&rq, t->srv->queue_mgt);
5316
willy tarreaue3b30652006-05-21 16:23:22 +02005317 if (t->srv)
5318 t->srv->failed_conns++;
5319 t->proxy->failed_conns++;
5320
willy tarreaudfece232006-05-02 00:19:57 +02005321 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
5322 t->srv = NULL; /* it's left to the dispatcher to choose a server */
5323 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
5324 t->flags &= ~SN_CK_MASK;
5325 t->flags |= SN_CK_DOWN;
5326 }
5327 return 0;
5328}
5329
5330/* This function performs the "redispatch" part of a connection attempt. It
5331 * will assign a server if required, queue the connection if required, and
5332 * handle errors that might arise at this level. It can change the server
5333 * state. It will return 1 if it encounters an error, switches the server
5334 * state, or has to queue a connection. Otherwise, it will return 0 indicating
5335 * that the connection is ready to use.
5336 */
5337
5338int srv_redispatch_connect(struct session *t) {
5339 int conn_err;
5340
5341 /* We know that we don't have any connection pending, so we will
5342 * try to get a new one, and wait in this state if it's queued
5343 */
5344 conn_err = assign_server_and_queue(t);
5345 switch (conn_err) {
5346 case SRV_STATUS_OK:
5347 break;
5348
5349 case SRV_STATUS_NOSRV:
willy tarreau59a6cc22006-05-12 01:29:08 +02005350 /* note: it is guaranteed that t->srv == NULL here */
willy tarreaudfece232006-05-02 00:19:57 +02005351 tv_eternity(&t->cnexpire);
5352 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
5353 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaue3b30652006-05-21 16:23:22 +02005354 if (t->srv)
5355 t->srv->failed_conns++;
5356 t->proxy->failed_conns++;
5357
willy tarreaudfece232006-05-02 00:19:57 +02005358 return 1;
5359
5360 case SRV_STATUS_QUEUED:
willy tarreau45526ed2006-05-03 20:11:50 +02005361 /* FIXME-20060503 : we should use the queue timeout instead */
5362 if (t->proxy->contimeout)
5363 tv_delayfrom(&t->cnexpire, &now, t->proxy->contimeout);
5364 else
5365 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02005366 t->srv_state = SV_STIDLE;
5367 /* do nothing else and do not wake any other session up */
5368 return 1;
5369
5370 case SRV_STATUS_FULL:
5371 case SRV_STATUS_INTERNAL:
5372 default:
5373 tv_eternity(&t->cnexpire);
5374 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
5375 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreaue3b30652006-05-21 16:23:22 +02005376 if (t->srv)
5377 t->srv->failed_conns++;
5378 t->proxy->failed_conns++;
5379
willy tarreaudfece232006-05-02 00:19:57 +02005380 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02005381 if (may_dequeue_tasks(t->srv, t->proxy))
5382 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005383 return 1;
5384 }
5385 /* if we get here, it's because we got SRV_STATUS_OK, which also
5386 * means that the connection has not been queued.
5387 */
5388 return 0;
5389}
5390
5391
5392/*
willy tarreau0f7af912005-12-17 12:21:26 +01005393 * manages the server FSM and its socket. It returns 1 if a state has changed
5394 * (and a resync may be needed), 0 else.
5395 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005396int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01005397 int s = t->srv_state;
5398 int c = t->cli_state;
5399 struct buffer *req = t->req;
5400 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01005401 appsess *asession_temp = NULL;
5402 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01005403 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01005404
willy tarreau750a4722005-12-17 13:21:24 +01005405#ifdef DEBUG_FULL
5406 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
5407#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01005408 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
5409 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
5410 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
5411 //);
willy tarreau0f7af912005-12-17 12:21:26 +01005412 if (s == SV_STIDLE) {
5413 if (c == CL_STHEADERS)
5414 return 0; /* stay in idle, waiting for data to reach the client side */
willy tarreau03a92de2006-05-21 18:26:53 +02005415 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
5416 (c == CL_STSHUTR &&
5417 (t->req->l == 0 || t->proxy->options & PR_O_ABRT_CLOSE))) { /* give up */
willy tarreau0f7af912005-12-17 12:21:26 +01005418 tv_eternity(&t->cnexpire);
willy tarreau424e04a2006-05-13 16:08:47 +02005419 if (t->pend_pos)
5420 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreau51e91292006-05-14 23:29:47 +02005421 /* note that this must not return any error because it would be able to
5422 * overwrite the client_retnclose() output.
5423 */
willy tarreau078c79a2006-05-13 12:23:58 +02005424 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 +02005425
willy tarreau0f7af912005-12-17 12:21:26 +01005426 return 1;
5427 }
willy tarreaudfece232006-05-02 00:19:57 +02005428 else {
5429 /* Right now, we will need to create a connection to the server.
5430 * We might already have tried, and got a connection pending, in
5431 * which case we will not do anything till it's pending. It's up
5432 * to any other session to release it and wake us up again.
5433 */
willy tarreau45526ed2006-05-03 20:11:50 +02005434 if (t->pend_pos) {
5435 if (tv_cmp2_ms(&t->cnexpire, &now) > 0)
5436 return 0;
5437 else {
5438 /* we've been waiting too long here */
5439 tv_eternity(&t->cnexpire);
willy tarreau078c79a2006-05-13 12:23:58 +02005440 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
5441 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
willy tarreau45526ed2006-05-03 20:11:50 +02005442 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaue3b30652006-05-21 16:23:22 +02005443 if (t->srv)
5444 t->srv->failed_conns++;
5445 t->proxy->failed_conns++;
willy tarreau45526ed2006-05-03 20:11:50 +02005446 return 1;
5447 }
5448 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005449
willy tarreaudfece232006-05-02 00:19:57 +02005450 do {
5451 /* first, get a connection */
5452 if (srv_redispatch_connect(t))
5453 return t->srv_state != SV_STIDLE;
5454
5455 /* try to (re-)connect to the server, and fail if we expire the
5456 * number of retries.
5457 */
willy tarreauf32f5242006-05-02 22:54:52 +02005458 if (srv_retryable_connect(t)) {
5459 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02005460 return t->srv_state != SV_STIDLE;
willy tarreauf32f5242006-05-02 22:54:52 +02005461 }
willy tarreaudfece232006-05-02 00:19:57 +02005462
5463 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01005464 }
5465 }
5466 else if (s == SV_STCONN) { /* connection in progress */
willy tarreau03a92de2006-05-21 18:26:53 +02005467 if (c == CL_STCLOSE || c == CL_STSHUTW ||
5468 (c == CL_STSHUTR &&
5469 (t->req->l == 0 || t->proxy->options & PR_O_ABRT_CLOSE))) { /* give up */
5470 tv_eternity(&t->cnexpire);
5471 fd_delete(t->srv_fd);
5472 if (t->srv)
5473 t->srv->cur_sess--;
5474
5475 /* note that this must not return any error because it would be able to
5476 * overwrite the client_retnclose() output.
5477 */
5478 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, 0, NULL);
5479 return 1;
5480 }
willy tarreau0f7af912005-12-17 12:21:26 +01005481 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01005482 //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 +01005483 return 0; /* nothing changed */
5484 }
5485 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
willy tarreaudfece232006-05-02 00:19:57 +02005486 /* timeout, asynchronous connect error or first write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005487 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
willy tarreaudfece232006-05-02 00:19:57 +02005488
willy tarreau0f7af912005-12-17 12:21:26 +01005489 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005490 if (t->srv)
5491 t->srv->cur_sess--;
willy tarreaudfece232006-05-02 00:19:57 +02005492
5493 if (t->res_sw == RES_SILENT)
willy tarreaub1285d52005-12-18 01:20:14 +01005494 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
5495 else
willy tarreaudfece232006-05-02 00:19:57 +02005496 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
willy tarreaub1285d52005-12-18 01:20:14 +01005497
willy tarreaudfece232006-05-02 00:19:57 +02005498 /* ensure that we have enough retries left */
5499 if (srv_count_retry_down(t, conn_err))
5500 return 1;
5501
5502 do {
5503 /* Now we will try to either reconnect to the same server or
5504 * connect to another server. If the connection gets queued
5505 * because all servers are saturated, then we will go back to
5506 * the SV_STIDLE state.
5507 */
willy tarreauf32f5242006-05-02 22:54:52 +02005508 if (srv_retryable_connect(t)) {
5509 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02005510 return t->srv_state != SV_STCONN;
willy tarreauf32f5242006-05-02 22:54:52 +02005511 }
willy tarreaudfece232006-05-02 00:19:57 +02005512
5513 /* we need to redispatch the connection to another server */
5514 if (srv_redispatch_connect(t))
5515 return t->srv_state != SV_STCONN;
5516 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01005517 }
5518 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01005519 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005520
willy tarreau0f7af912005-12-17 12:21:26 +01005521 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005522 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01005523 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005524 tv_eternity(&t->swexpire);
5525 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01005526 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005527 if (t->proxy->srvtimeout) {
5528 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005529 /* FIXME: to prevent the server from expiring read timeouts during writes,
5530 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005531 t->srexpire = t->swexpire;
5532 }
5533 else
5534 tv_eternity(&t->swexpire);
5535 }
willy tarreau0f7af912005-12-17 12:21:26 +01005536
5537 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
5538 FD_SET(t->srv_fd, StaticReadEvent);
5539 if (t->proxy->srvtimeout)
5540 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5541 else
5542 tv_eternity(&t->srexpire);
5543
5544 t->srv_state = SV_STDATA;
willy tarreau2d505e52006-05-21 08:32:50 +02005545 if (t->srv)
5546 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01005547 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01005548
5549 /* if the user wants to log as soon as possible, without counting
5550 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005551 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005552 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
5553 sess_log(t);
5554 }
willy tarreau0f7af912005-12-17 12:21:26 +01005555 }
willy tarreauef900ab2005-12-17 12:52:52 +01005556 else {
willy tarreau0f7af912005-12-17 12:21:26 +01005557 t->srv_state = SV_STHEADERS;
willy tarreau2d505e52006-05-21 08:32:50 +02005558 if (t->srv)
5559 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01005560 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
5561 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005562 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005563 return 1;
5564 }
5565 }
5566 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005567 /* now parse the partial (or complete) headers */
5568 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
5569 char *ptr;
5570 int delete_header;
5571
5572 ptr = rep->lr;
5573
5574 /* look for the end of the current header */
5575 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
5576 ptr++;
5577
5578 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005579 int line, len;
5580
5581 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01005582
5583 /* first, we'll block if security checks have caught nasty things */
5584 if (t->flags & SN_CACHEABLE) {
5585 if ((t->flags & SN_CACHE_COOK) &&
5586 (t->flags & SN_SCK_ANY) &&
5587 (t->proxy->options & PR_O_CHK_CACHE)) {
5588
5589 /* we're in presence of a cacheable response containing
5590 * a set-cookie header. We'll block it as requested by
5591 * the 'checkcache' option, and send an alert.
5592 */
5593 tv_eternity(&t->srexpire);
5594 tv_eternity(&t->swexpire);
5595 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02005596 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02005597 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02005598 t->srv->failed_secu++;
5599 }
5600 t->proxy->failed_secu++;
willy tarreau97f58572005-12-18 00:53:44 +01005601 t->srv_state = SV_STCLOSE;
5602 t->logs.status = 502;
5603 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
5604 if (!(t->flags & SN_ERR_MASK))
5605 t->flags |= SN_ERR_PRXCOND;
5606 if (!(t->flags & SN_FINST_MASK))
5607 t->flags |= SN_FINST_H;
5608
5609 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
5610 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
5611
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 tarreau97f58572005-12-18 00:53:44 +01005618 return 1;
5619 }
5620 }
5621
willy tarreau982249e2005-12-18 00:57:06 +01005622 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
5623 if (t->flags & SN_SVDENY) {
5624 tv_eternity(&t->srexpire);
5625 tv_eternity(&t->swexpire);
5626 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02005627 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02005628 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02005629 t->srv->failed_secu++;
5630 }
5631 t->proxy->failed_secu++;
willy tarreau982249e2005-12-18 00:57:06 +01005632 t->srv_state = SV_STCLOSE;
5633 t->logs.status = 502;
5634 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
5635 if (!(t->flags & SN_ERR_MASK))
5636 t->flags |= SN_ERR_PRXCOND;
5637 if (!(t->flags & SN_FINST_MASK))
5638 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005639 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005640 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005641 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005642 if (may_dequeue_tasks(t->srv, t->proxy))
5643 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005644
willy tarreau982249e2005-12-18 00:57:06 +01005645 return 1;
5646 }
5647
willy tarreau5cbea6f2005-12-17 12:48:26 +01005648 /* we'll have something else to do here : add new headers ... */
5649
willy tarreaucd878942005-12-17 13:27:43 +01005650 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
5651 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005652 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01005653 * insert a set-cookie here, except if we want to insert only on POST
willy tarreau4f7a1012006-05-09 23:32:26 +02005654 * requests and this one isn't. Note that servers which don't have cookies
5655 * (eg: some backup servers) will return a full cookie removal request.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005656 */
willy tarreau750a4722005-12-17 13:21:24 +01005657 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01005658 t->proxy->cookie_name,
willy tarreau4f7a1012006-05-09 23:32:26 +02005659 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
willy tarreau750a4722005-12-17 13:21:24 +01005660
willy tarreau036e1ce2005-12-17 13:46:33 +01005661 t->flags |= SN_SCK_INSERTED;
5662
willy tarreau750a4722005-12-17 13:21:24 +01005663 /* Here, we will tell an eventual cache on the client side that we don't
5664 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
5665 * Some caches understand the correct form: 'no-cache="set-cookie"', but
5666 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
5667 */
willy tarreau240afa62005-12-17 13:14:35 +01005668 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01005669 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
5670 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01005671
5672 if (rep->data + rep->l < rep->h)
5673 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
5674 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01005675 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005676 }
5677
5678 /* headers to be added */
5679 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01005680 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
5681 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005682 }
5683
willy tarreau25c4ea52005-12-18 00:49:49 +01005684 /* add a "connection: close" line if needed */
5685 if (t->proxy->options & PR_O_HTTP_CLOSE)
5686 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
5687
willy tarreau5cbea6f2005-12-17 12:48:26 +01005688 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01005689 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01005690 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01005691
Willy TARREAU767ba712006-03-01 22:40:50 +01005692 /* client connection already closed or option 'httpclose' required :
5693 * we close the server's outgoing connection right now.
5694 */
5695 if ((req->l == 0) &&
5696 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
5697 FD_CLR(t->srv_fd, StaticWriteEvent);
5698 tv_eternity(&t->swexpire);
5699
5700 /* We must ensure that the read part is still alive when switching
5701 * to shutw */
5702 FD_SET(t->srv_fd, StaticReadEvent);
5703 if (t->proxy->srvtimeout)
5704 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5705
5706 shutdown(t->srv_fd, SHUT_WR);
5707 t->srv_state = SV_STSHUTW;
5708 }
5709
willy tarreau25c4ea52005-12-18 00:49:49 +01005710 /* if the user wants to log as soon as possible, without counting
5711 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005712 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005713 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
5714 t->logs.bytes = rep->h - rep->data;
5715 sess_log(t);
5716 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005717 break;
5718 }
5719
5720 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
5721 if (ptr > rep->r - 2) {
5722 /* this is a partial header, let's wait for more to come */
5723 rep->lr = ptr;
5724 break;
5725 }
5726
5727 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
5728 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
5729
5730 /* now we know that *ptr is either \r or \n,
5731 * and that there are at least 1 char after it.
5732 */
5733 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
5734 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
5735 else
5736 rep->lr = ptr + 2; /* \r\n or \n\r */
5737
5738 /*
5739 * now we know that we have a full header ; we can do whatever
5740 * we want with these pointers :
5741 * rep->h = beginning of header
5742 * ptr = end of header (first \r or \n)
5743 * rep->lr = beginning of next line (next rep->h)
5744 * rep->r = end of data (not used at this stage)
5745 */
5746
willy tarreaua1598082005-12-17 13:08:06 +01005747
willy tarreau982249e2005-12-18 00:57:06 +01005748 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01005749 t->logs.logwait &= ~LW_RESP;
5750 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01005751 switch (t->logs.status) {
5752 case 200:
5753 case 203:
5754 case 206:
5755 case 300:
5756 case 301:
5757 case 410:
5758 /* RFC2616 @13.4:
5759 * "A response received with a status code of
5760 * 200, 203, 206, 300, 301 or 410 MAY be stored
5761 * by a cache (...) unless a cache-control
5762 * directive prohibits caching."
5763 *
5764 * RFC2616 @9.5: POST method :
5765 * "Responses to this method are not cacheable,
5766 * unless the response includes appropriate
5767 * Cache-Control or Expires header fields."
5768 */
willy tarreau7476ec92006-05-21 16:24:15 +02005769 if (!(t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
willy tarreau982249e2005-12-18 00:57:06 +01005770 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
5771 break;
5772 default:
5773 break;
5774 }
willy tarreau4302f492005-12-18 01:00:37 +01005775 }
5776 else if (t->logs.logwait & LW_RSPHDR) {
5777 struct cap_hdr *h;
5778 int len;
5779 for (h = t->proxy->rsp_cap; h; h = h->next) {
5780 if ((h->namelen + 2 <= ptr - rep->h) &&
5781 (rep->h[h->namelen] == ':') &&
5782 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
5783
5784 if (t->rsp_cap[h->index] == NULL)
5785 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
5786
5787 len = ptr - (rep->h + h->namelen + 2);
5788 if (len > h->len)
5789 len = h->len;
5790
5791 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
5792 t->rsp_cap[h->index][len]=0;
5793 }
5794 }
5795
willy tarreaua1598082005-12-17 13:08:06 +01005796 }
5797
willy tarreau5cbea6f2005-12-17 12:48:26 +01005798 delete_header = 0;
5799
willy tarreau982249e2005-12-18 00:57:06 +01005800 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005801 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01005802 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 +01005803 max = ptr - rep->h;
5804 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01005805 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005806 trash[len++] = '\n';
5807 write(1, trash, len);
5808 }
5809
willy tarreau25c4ea52005-12-18 00:49:49 +01005810 /* remove "connection: " if needed */
5811 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
5812 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
5813 delete_header = 1;
5814 }
5815
willy tarreau5cbea6f2005-12-17 12:48:26 +01005816 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01005817 if (!delete_header && t->proxy->rsp_exp != NULL
5818 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01005819 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005820 char term;
5821
5822 term = *ptr;
5823 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01005824 exp = t->proxy->rsp_exp;
5825 do {
5826 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
5827 switch (exp->action) {
5828 case ACT_ALLOW:
5829 if (!(t->flags & SN_SVDENY))
5830 t->flags |= SN_SVALLOW;
5831 break;
5832 case ACT_REPLACE:
5833 if (!(t->flags & SN_SVDENY)) {
5834 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
5835 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
5836 }
5837 break;
5838 case ACT_REMOVE:
5839 if (!(t->flags & SN_SVDENY))
5840 delete_header = 1;
5841 break;
5842 case ACT_DENY:
5843 if (!(t->flags & SN_SVALLOW))
5844 t->flags |= SN_SVDENY;
5845 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01005846 case ACT_PASS: /* we simply don't deny this one */
5847 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005848 }
5849 break;
5850 }
willy tarreaue39cd132005-12-17 13:00:18 +01005851 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005852 *ptr = term; /* restore the string terminator */
5853 }
5854
willy tarreau97f58572005-12-18 00:53:44 +01005855 /* check for cache-control: or pragma: headers */
5856 if (!delete_header && (t->flags & SN_CACHEABLE)) {
5857 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
5858 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5859 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
5860 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01005861 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01005862 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5863 else {
5864 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01005865 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005866 t->flags &= ~SN_CACHE_COOK;
5867 }
5868 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005869 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005870 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005871 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01005872 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5873 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005874 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01005875 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01005876 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
5877 (rep->h + 25 == ptr || rep->h[25] == ',')) {
5878 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5879 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
5880 (rep->h + 21 == ptr || rep->h[21] == ',')) {
5881 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01005882 }
5883 }
5884 }
5885
willy tarreau5cbea6f2005-12-17 12:48:26 +01005886 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01005887 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01005888 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01005889 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005890 char *p1, *p2, *p3, *p4;
5891
willy tarreau97f58572005-12-18 00:53:44 +01005892 t->flags |= SN_SCK_ANY;
5893
willy tarreau5cbea6f2005-12-17 12:48:26 +01005894 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
5895
5896 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01005897 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005898 p1++;
5899
5900 if (p1 == ptr || *p1 == ';') /* end of cookie */
5901 break;
5902
5903 /* p1 is at the beginning of the cookie name */
5904 p2 = p1;
5905
5906 while (p2 < ptr && *p2 != '=' && *p2 != ';')
5907 p2++;
5908
5909 if (p2 == ptr || *p2 == ';') /* next cookie */
5910 break;
5911
5912 p3 = p2 + 1; /* skips the '=' sign */
5913 if (p3 == ptr)
5914 break;
5915
5916 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01005917 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01005918 p4++;
5919
5920 /* here, we have the cookie name between p1 and p2,
5921 * and its value between p3 and p4.
5922 * we can process it.
5923 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005924
5925 /* first, let's see if we want to capture it */
5926 if (t->proxy->capture_name != NULL &&
5927 t->logs.srv_cookie == NULL &&
5928 (p4 - p1 >= t->proxy->capture_namelen) &&
5929 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
5930 int log_len = p4 - p1;
5931
5932 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
5933 Alert("HTTP logging : out of memory.\n");
5934 }
5935
5936 if (log_len > t->proxy->capture_len)
5937 log_len = t->proxy->capture_len;
5938 memcpy(t->logs.srv_cookie, p1, log_len);
5939 t->logs.srv_cookie[log_len] = 0;
5940 }
5941
5942 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
5943 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005944 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01005945 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005946
5947 /* If the cookie is in insert mode on a known server, we'll delete
5948 * this occurrence because we'll insert another one later.
5949 * We'll delete it too if the "indirect" option is set and we're in
5950 * a direct access. */
5951 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01005952 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005953 /* this header must be deleted */
5954 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01005955 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005956 }
5957 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
5958 /* replace bytes p3->p4 with the cookie name associated
5959 * with this server since we know it.
5960 */
5961 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01005962 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005963 }
willy tarreau0174f312005-12-18 01:02:42 +01005964 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
5965 /* insert the cookie name associated with this server
5966 * before existing cookie, and insert a delimitor between them..
5967 */
5968 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
5969 p3[t->srv->cklen] = COOKIE_DELIM;
5970 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
5971 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005972 break;
5973 }
willy tarreau12350152005-12-18 01:03:27 +01005974
5975 /* first, let's see if the cookie is our appcookie*/
5976 if ((t->proxy->appsession_name != NULL) &&
5977 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
5978
5979 /* Cool... it's the right one */
5980
willy tarreaub952e1d2005-12-18 01:31:20 +01005981 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01005982 asession_temp = &local_asession;
5983
willy tarreaub952e1d2005-12-18 01:31:20 +01005984 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005985 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5986 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5987 }
5988 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
5989 asession_temp->sessid[t->proxy->appsession_len] = 0;
5990 asession_temp->serverid = NULL;
5991
5992 /* only do insert, if lookup fails */
5993 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
5994 if ((asession_temp = pool_alloc(appsess)) == NULL) {
5995 Alert("Not enought Memory process_srv():asession:calloc().\n");
5996 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
5997 return 0;
5998 }
5999 asession_temp->sessid = local_asession.sessid;
6000 asession_temp->serverid = local_asession.serverid;
6001 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01006002 }/* end if (chtbl_lookup()) */
6003 else {
willy tarreau12350152005-12-18 01:03:27 +01006004 /* free wasted memory */
6005 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01006006 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01006007
willy tarreaub952e1d2005-12-18 01:31:20 +01006008 if (asession_temp->serverid == NULL) {
6009 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01006010 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
6011 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
6012 }
6013 asession_temp->serverid[0] = '\0';
6014 }
6015
willy tarreaub952e1d2005-12-18 01:31:20 +01006016 if (asession_temp->serverid[0] == '\0')
6017 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01006018
6019 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
6020
6021#if defined(DEBUG_HASH)
6022 print_table(&(t->proxy->htbl_proxy));
6023#endif
6024 break;
6025 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006026 else {
6027 // fprintf(stderr,"Ignoring unknown cookie : ");
6028 // write(2, p1, p2-p1);
6029 // fprintf(stderr," = ");
6030 // write(2, p3, p4-p3);
6031 // fprintf(stderr,"\n");
6032 }
6033 break; /* we don't want to loop again since there cannot be another cookie on the same line */
6034 } /* we're now at the end of the cookie value */
6035 } /* end of cookie processing */
6036
willy tarreau97f58572005-12-18 00:53:44 +01006037 /* check for any set-cookie in case we check for cacheability */
6038 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
6039 (t->proxy->options & PR_O_CHK_CACHE) &&
6040 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
6041 t->flags |= SN_SCK_ANY;
6042 }
6043
willy tarreau5cbea6f2005-12-17 12:48:26 +01006044 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01006045 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006046 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01006047
willy tarreau5cbea6f2005-12-17 12:48:26 +01006048 rep->h = rep->lr;
6049 } /* while (rep->lr < rep->r) */
6050
6051 /* end of header processing (even if incomplete) */
6052
willy tarreauef900ab2005-12-17 12:52:52 +01006053 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6054 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
6055 * full. We cannot loop here since event_srv_read will disable it only if
6056 * rep->l == rlim-data
6057 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006058 FD_SET(t->srv_fd, StaticReadEvent);
6059 if (t->proxy->srvtimeout)
6060 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6061 else
6062 tv_eternity(&t->srexpire);
6063 }
willy tarreau0f7af912005-12-17 12:21:26 +01006064
willy tarreau8337c6b2005-12-17 13:41:01 +01006065 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01006066 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01006067 tv_eternity(&t->srexpire);
6068 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006069 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006070 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006071 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006072 t->srv->failed_resp++;
6073 }
6074 t->proxy->failed_resp++;
6075
willy tarreau0f7af912005-12-17 12:21:26 +01006076 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01006077 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01006078 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01006079 if (!(t->flags & SN_ERR_MASK))
6080 t->flags |= SN_ERR_SRVCL;
6081 if (!(t->flags & SN_FINST_MASK))
6082 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02006083 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006084 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006085 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006086 if (may_dequeue_tasks(t->srv, t->proxy))
6087 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006088
willy tarreau0f7af912005-12-17 12:21:26 +01006089 return 1;
6090 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006091 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01006092 * since we are in header mode, if there's no space left for headers, we
6093 * won't be able to free more later, so the session will never terminate.
6094 */
willy tarreau8337c6b2005-12-17 13:41:01 +01006095 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 +01006096 FD_CLR(t->srv_fd, StaticReadEvent);
6097 tv_eternity(&t->srexpire);
6098 shutdown(t->srv_fd, SHUT_RD);
6099 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01006100 //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 +01006101 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006102 }
6103 /* read timeout : return a 504 to the client.
6104 */
6105 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6106 tv_eternity(&t->srexpire);
6107 tv_eternity(&t->swexpire);
6108 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006109 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006110 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006111 t->srv->failed_resp++;
6112 }
6113 t->proxy->failed_resp++;
willy tarreau8337c6b2005-12-17 13:41:01 +01006114 t->srv_state = SV_STCLOSE;
6115 t->logs.status = 504;
6116 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01006117 if (!(t->flags & SN_ERR_MASK))
6118 t->flags |= SN_ERR_SRVTO;
6119 if (!(t->flags & SN_FINST_MASK))
6120 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02006121 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006122 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006123 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006124 if (may_dequeue_tasks(t->srv, t->proxy))
6125 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006126
willy tarreau8337c6b2005-12-17 13:41:01 +01006127 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006128 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006129 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01006130 /* FIXME!!! here, we don't want to switch to SHUTW if the
6131 * client shuts read too early, because we may still have
6132 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01006133 * The side-effect is that if the client completely closes its
6134 * connection during SV_STHEADER, the connection to the server
6135 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01006136 */
willy tarreau036e1ce2005-12-17 13:46:33 +01006137 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01006138 FD_CLR(t->srv_fd, StaticWriteEvent);
6139 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01006140
6141 /* We must ensure that the read part is still alive when switching
6142 * to shutw */
6143 FD_SET(t->srv_fd, StaticReadEvent);
6144 if (t->proxy->srvtimeout)
6145 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6146
willy tarreau0f7af912005-12-17 12:21:26 +01006147 shutdown(t->srv_fd, SHUT_WR);
6148 t->srv_state = SV_STSHUTW;
6149 return 1;
6150 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006151 /* write timeout */
6152 /* FIXME!!! here, we don't want to switch to SHUTW if the
6153 * client shuts read too early, because we may still have
6154 * some work to do on the headers.
6155 */
6156 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
6157 FD_CLR(t->srv_fd, StaticWriteEvent);
6158 tv_eternity(&t->swexpire);
6159 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006160 /* We must ensure that the read part is still alive when switching
6161 * to shutw */
6162 FD_SET(t->srv_fd, StaticReadEvent);
6163 if (t->proxy->srvtimeout)
6164 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6165
6166 /* We must ensure that the read part is still alive when switching
6167 * to shutw */
6168 FD_SET(t->srv_fd, StaticReadEvent);
6169 if (t->proxy->srvtimeout)
6170 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6171
willy tarreau036e1ce2005-12-17 13:46:33 +01006172 t->srv_state = SV_STSHUTW;
6173 if (!(t->flags & SN_ERR_MASK))
6174 t->flags |= SN_ERR_SRVTO;
6175 if (!(t->flags & SN_FINST_MASK))
6176 t->flags |= SN_FINST_H;
6177 return 1;
6178 }
willy tarreau0f7af912005-12-17 12:21:26 +01006179
6180 if (req->l == 0) {
6181 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6182 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6183 tv_eternity(&t->swexpire);
6184 }
6185 }
6186 else { /* client buffer not empty */
6187 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6188 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006189 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006190 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006191 /* FIXME: to prevent the server from expiring read timeouts during writes,
6192 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006193 t->srexpire = t->swexpire;
6194 }
willy tarreau0f7af912005-12-17 12:21:26 +01006195 else
6196 tv_eternity(&t->swexpire);
6197 }
6198 }
6199
willy tarreau5cbea6f2005-12-17 12:48:26 +01006200 /* be nice with the client side which would like to send a complete header
6201 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
6202 * would read all remaining data at once ! The client should not write past rep->lr
6203 * when the server is in header state.
6204 */
6205 //return header_processed;
6206 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01006207 }
6208 else if (s == SV_STDATA) {
6209 /* read or write error */
6210 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01006211 tv_eternity(&t->srexpire);
6212 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006213 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006214 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006215 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006216 t->srv->failed_resp++;
6217 }
6218 t->proxy->failed_resp++;
willy tarreau0f7af912005-12-17 12:21:26 +01006219 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01006220 if (!(t->flags & SN_ERR_MASK))
6221 t->flags |= SN_ERR_SRVCL;
6222 if (!(t->flags & SN_FINST_MASK))
6223 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006224 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006225 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006226 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006227 if (may_dequeue_tasks(t->srv, t->proxy))
6228 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006229
willy tarreau0f7af912005-12-17 12:21:26 +01006230 return 1;
6231 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006232 /* last read, or end of client write */
6233 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01006234 FD_CLR(t->srv_fd, StaticReadEvent);
6235 tv_eternity(&t->srexpire);
6236 shutdown(t->srv_fd, SHUT_RD);
6237 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01006238 //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 +01006239 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01006240 }
6241 /* end of client read and no more data to send */
6242 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
6243 FD_CLR(t->srv_fd, StaticWriteEvent);
6244 tv_eternity(&t->swexpire);
6245 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006246 /* We must ensure that the read part is still alive when switching
6247 * to shutw */
6248 FD_SET(t->srv_fd, StaticReadEvent);
6249 if (t->proxy->srvtimeout)
6250 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6251
willy tarreaua41a8b42005-12-17 14:02:24 +01006252 t->srv_state = SV_STSHUTW;
6253 return 1;
6254 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006255 /* read timeout */
6256 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6257 FD_CLR(t->srv_fd, StaticReadEvent);
6258 tv_eternity(&t->srexpire);
6259 shutdown(t->srv_fd, SHUT_RD);
6260 t->srv_state = SV_STSHUTR;
6261 if (!(t->flags & SN_ERR_MASK))
6262 t->flags |= SN_ERR_SRVTO;
6263 if (!(t->flags & SN_FINST_MASK))
6264 t->flags |= SN_FINST_D;
6265 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006266 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006267 /* write timeout */
6268 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01006269 FD_CLR(t->srv_fd, StaticWriteEvent);
6270 tv_eternity(&t->swexpire);
6271 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006272 /* We must ensure that the read part is still alive when switching
6273 * to shutw */
6274 FD_SET(t->srv_fd, StaticReadEvent);
6275 if (t->proxy->srvtimeout)
6276 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01006277 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01006278 if (!(t->flags & SN_ERR_MASK))
6279 t->flags |= SN_ERR_SRVTO;
6280 if (!(t->flags & SN_FINST_MASK))
6281 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01006282 return 1;
6283 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01006284
6285 /* recompute request time-outs */
6286 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01006287 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6288 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6289 tv_eternity(&t->swexpire);
6290 }
6291 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01006292 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01006293 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6294 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006295 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006296 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006297 /* FIXME: to prevent the server from expiring read timeouts during writes,
6298 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006299 t->srexpire = t->swexpire;
6300 }
willy tarreau0f7af912005-12-17 12:21:26 +01006301 else
6302 tv_eternity(&t->swexpire);
6303 }
6304 }
6305
willy tarreaub1ff9db2005-12-17 13:51:03 +01006306 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01006307 if (rep->l == BUFSIZE) { /* no room to read more data */
6308 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
6309 FD_CLR(t->srv_fd, StaticReadEvent);
6310 tv_eternity(&t->srexpire);
6311 }
6312 }
6313 else {
6314 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6315 FD_SET(t->srv_fd, StaticReadEvent);
6316 if (t->proxy->srvtimeout)
6317 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6318 else
6319 tv_eternity(&t->srexpire);
6320 }
6321 }
6322
6323 return 0; /* other cases change nothing */
6324 }
6325 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006326 if (t->res_sw == RES_ERROR) {
6327 //FD_CLR(t->srv_fd, StaticWriteEvent);
6328 tv_eternity(&t->swexpire);
6329 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006330 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006331 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006332 t->srv->failed_resp++;
6333 }
6334 t->proxy->failed_resp++;
willy tarreau036e1ce2005-12-17 13:46:33 +01006335 //close(t->srv_fd);
6336 t->srv_state = SV_STCLOSE;
6337 if (!(t->flags & SN_ERR_MASK))
6338 t->flags |= SN_ERR_SRVCL;
6339 if (!(t->flags & SN_FINST_MASK))
6340 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006341 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006342 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006343 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006344 if (may_dequeue_tasks(t->srv, t->proxy))
6345 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006346
willy tarreau036e1ce2005-12-17 13:46:33 +01006347 return 1;
6348 }
6349 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006350 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01006351 tv_eternity(&t->swexpire);
6352 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006353 if (t->srv)
6354 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006355 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01006356 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02006357 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006358 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006359 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006360 if (may_dequeue_tasks(t->srv, t->proxy))
6361 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006362
willy tarreau0f7af912005-12-17 12:21:26 +01006363 return 1;
6364 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006365 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
6366 //FD_CLR(t->srv_fd, StaticWriteEvent);
6367 tv_eternity(&t->swexpire);
6368 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006369 if (t->srv)
6370 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006371 //close(t->srv_fd);
6372 t->srv_state = SV_STCLOSE;
6373 if (!(t->flags & SN_ERR_MASK))
6374 t->flags |= SN_ERR_SRVTO;
6375 if (!(t->flags & SN_FINST_MASK))
6376 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006377 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006378 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006379 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006380 if (may_dequeue_tasks(t->srv, t->proxy))
6381 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006382
willy tarreau036e1ce2005-12-17 13:46:33 +01006383 return 1;
6384 }
willy tarreau0f7af912005-12-17 12:21:26 +01006385 else if (req->l == 0) {
6386 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6387 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6388 tv_eternity(&t->swexpire);
6389 }
6390 }
6391 else { /* buffer not empty */
6392 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6393 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006394 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006395 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006396 /* FIXME: to prevent the server from expiring read timeouts during writes,
6397 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006398 t->srexpire = t->swexpire;
6399 }
willy tarreau0f7af912005-12-17 12:21:26 +01006400 else
6401 tv_eternity(&t->swexpire);
6402 }
6403 }
6404 return 0;
6405 }
6406 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006407 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006408 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01006409 tv_eternity(&t->srexpire);
6410 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006411 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006412 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006413 t->srv->failed_resp++;
6414 }
6415 t->proxy->failed_resp++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006416 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01006417 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01006418 if (!(t->flags & SN_ERR_MASK))
6419 t->flags |= SN_ERR_SRVCL;
6420 if (!(t->flags & SN_FINST_MASK))
6421 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006422 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006423 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006424 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006425 if (may_dequeue_tasks(t->srv, t->proxy))
6426 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006427
willy tarreau0f7af912005-12-17 12:21:26 +01006428 return 1;
6429 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006430 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
6431 //FD_CLR(t->srv_fd, StaticReadEvent);
6432 tv_eternity(&t->srexpire);
6433 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006434 if (t->srv)
6435 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006436 //close(t->srv_fd);
6437 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02006438 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006439 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006440 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006441 if (may_dequeue_tasks(t->srv, t->proxy))
6442 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006443
willy tarreau036e1ce2005-12-17 13:46:33 +01006444 return 1;
6445 }
6446 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6447 //FD_CLR(t->srv_fd, StaticReadEvent);
6448 tv_eternity(&t->srexpire);
6449 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006450 if (t->srv)
6451 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006452 //close(t->srv_fd);
6453 t->srv_state = SV_STCLOSE;
6454 if (!(t->flags & SN_ERR_MASK))
6455 t->flags |= SN_ERR_SRVTO;
6456 if (!(t->flags & SN_FINST_MASK))
6457 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006458 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006459 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006460 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006461 if (may_dequeue_tasks(t->srv, t->proxy))
6462 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006463
willy tarreau036e1ce2005-12-17 13:46:33 +01006464 return 1;
6465 }
willy tarreau0f7af912005-12-17 12:21:26 +01006466 else if (rep->l == BUFSIZE) { /* no room to read more data */
6467 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
6468 FD_CLR(t->srv_fd, StaticReadEvent);
6469 tv_eternity(&t->srexpire);
6470 }
6471 }
6472 else {
6473 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6474 FD_SET(t->srv_fd, StaticReadEvent);
6475 if (t->proxy->srvtimeout)
6476 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6477 else
6478 tv_eternity(&t->srexpire);
6479 }
6480 }
6481 return 0;
6482 }
6483 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01006484 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01006485 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01006486 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 +01006487 write(1, trash, len);
6488 }
6489 return 0;
6490 }
6491 return 0;
6492}
6493
6494
willy tarreau5cbea6f2005-12-17 12:48:26 +01006495/* Processes the client and server jobs of a session task, then
6496 * puts it back to the wait queue in a clean state, or
6497 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01006498 * the time the task accepts to wait, or TIME_ETERNITY for
6499 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01006500 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006501int process_session(struct task *t) {
6502 struct session *s = t->context;
6503 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006504
willy tarreau5cbea6f2005-12-17 12:48:26 +01006505 do {
6506 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01006507 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006508 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01006509 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006510 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01006511 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006512 } while (fsm_resync);
6513
6514 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01006515 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006516 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01006517
willy tarreau5cbea6f2005-12-17 12:48:26 +01006518 tv_min(&min1, &s->crexpire, &s->cwexpire);
6519 tv_min(&min2, &s->srexpire, &s->swexpire);
6520 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01006521 tv_min(&t->expire, &min1, &min2);
6522
6523 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006524 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01006525
Willy TARREAU1cec83c2006-03-01 22:33:49 +01006526#ifdef DEBUG_FULL
6527 /* DEBUG code : this should never ever happen, otherwise it indicates
6528 * that a task still has something to do and will provoke a quick loop.
6529 */
6530 if (tv_remain2(&now, &t->expire) <= 0)
6531 exit(100);
6532#endif
6533
willy tarreaub952e1d2005-12-18 01:31:20 +01006534 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01006535 }
6536
willy tarreau5cbea6f2005-12-17 12:48:26 +01006537 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01006538 actconn--;
6539
willy tarreau982249e2005-12-18 00:57:06 +01006540 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01006541 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01006542 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 +01006543 write(1, trash, len);
6544 }
6545
willy tarreau750a4722005-12-17 13:21:24 +01006546 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01006547 if (s->rep != NULL)
6548 s->logs.bytes = s->rep->total;
6549
willy tarreau9fe663a2005-12-17 13:02:59 +01006550 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01006551 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01006552 sess_log(s);
6553
willy tarreau0f7af912005-12-17 12:21:26 +01006554 /* the task MUST not be in the run queue anymore */
6555 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006556 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01006557 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01006558 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006559}
6560
6561
willy tarreau2812edc2006-05-04 12:09:37 +02006562/* Sets server <s> down, notifies by all available means, recounts the
6563 * remaining servers on the proxy and transfers queued sessions whenever
6564 * possible to other servers.
6565 */
6566void set_server_down(struct server *s) {
6567 struct pendconn *pc, *pc_bck, *pc_end;
6568 struct session *sess;
6569 int xferred;
6570
6571 s->state &= ~SRV_RUNNING;
6572
6573 if (s->health == s->rise) {
6574 recount_servers(s->proxy);
6575 recalc_server_map(s->proxy);
6576
6577 /* we might have sessions queued on this server and waiting for
6578 * a connection. Those which are redispatchable will be queued
6579 * to another server or to the proxy itself.
6580 */
6581 xferred = 0;
6582 FOREACH_ITEM_SAFE(pc, pc_bck, &s->pendconns, pc_end, struct pendconn *, list) {
6583 sess = pc->sess;
6584 if ((sess->proxy->options & PR_O_REDISP)) {
6585 /* The REDISP option was specified. We will ignore
6586 * cookie and force to balance or use the dispatcher.
6587 */
6588 sess->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
6589 sess->srv = NULL; /* it's left to the dispatcher to choose a server */
6590 if ((sess->flags & SN_CK_MASK) == SN_CK_VALID) {
6591 sess->flags &= ~SN_CK_MASK;
6592 sess->flags |= SN_CK_DOWN;
6593 }
6594 pendconn_free(pc);
6595 task_wakeup(&rq, sess->task);
6596 xferred++;
6597 }
6598 }
6599
6600 sprintf(trash, "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s"
6601 " %d sessions active, %d requeued, %d remaining in queue.\n",
6602 s->state & SRV_BACKUP ? "Backup " : "",
6603 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6604 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6605 s->cur_sess, xferred, s->nbpend);
6606
willy tarreaubc2eda62006-05-04 15:16:23 +02006607 Warning("%s", trash);
6608 send_log(s->proxy, LOG_ALERT, "%s", trash);
willy tarreau2812edc2006-05-04 12:09:37 +02006609
6610 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
6611 Alert("Proxy %s has no server available !\n", s->proxy->id);
6612 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
6613 }
willy tarreaucb406512006-05-18 00:52:35 +02006614 s->down_trans++;
willy tarreau2812edc2006-05-04 12:09:37 +02006615 }
6616 s->health = 0; /* failure */
6617}
6618
6619
willy tarreau5cbea6f2005-12-17 12:48:26 +01006620
6621/*
6622 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01006623 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01006624 */
6625int process_chk(struct task *t) {
6626 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01006627 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01006628 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006629
willy tarreauef900ab2005-12-17 12:52:52 +01006630 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006631
willy tarreau25424f82006-03-19 19:37:48 +01006632 new_chk:
6633 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006634 if (fd < 0) { /* no check currently running */
6635 //fprintf(stderr, "process_chk: 2\n");
6636 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
6637 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006638 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006639 }
Willy TARREAU3759f982006-03-01 22:44:17 +01006640
6641 /* we don't send any health-checks when the proxy is stopped or when
6642 * the server should not be checked.
6643 */
6644 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01006645 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6646 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01006647 task_queue(t); /* restore t to its place in the task list */
6648 return tv_remain2(&now, &t->expire);
6649 }
6650
willy tarreau5cbea6f2005-12-17 12:48:26 +01006651 /* we'll initiate a new check */
6652 s->result = 0; /* no result yet */
6653 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006654 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01006655 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
6656 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
6657 //fprintf(stderr, "process_chk: 3\n");
6658
willy tarreaua41a8b42005-12-17 14:02:24 +01006659 /* we'll connect to the check port on the server */
6660 sa = s->addr;
6661 sa.sin_port = htons(s->check_port);
6662
willy tarreau0174f312005-12-18 01:02:42 +01006663 /* allow specific binding :
6664 * - server-specific at first
6665 * - proxy-specific next
6666 */
6667 if (s->state & SRV_BIND_SRC) {
6668 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
6669 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
6670 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
6671 s->proxy->id, s->id);
6672 s->result = -1;
6673 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006674 }
willy tarreau0174f312005-12-18 01:02:42 +01006675 else if (s->proxy->options & PR_O_BIND_SRC) {
6676 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
6677 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
6678 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
6679 s->proxy->id);
6680 s->result = -1;
6681 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006682 }
willy tarreau0174f312005-12-18 01:02:42 +01006683
6684 if (!s->result) {
6685 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
6686 /* OK, connection in progress or established */
6687
6688 //fprintf(stderr, "process_chk: 4\n");
6689
6690 s->curfd = fd; /* that's how we know a test is in progress ;-) */
6691 fdtab[fd].owner = t;
6692 fdtab[fd].read = &event_srv_chk_r;
6693 fdtab[fd].write = &event_srv_chk_w;
6694 fdtab[fd].state = FD_STCONN; /* connection in progress */
6695 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01006696#ifdef DEBUG_FULL
6697 assert (!FD_ISSET(fd, StaticReadEvent));
6698#endif
willy tarreau0174f312005-12-18 01:02:42 +01006699 fd_insert(fd);
6700 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
6701 tv_delayfrom(&t->expire, &now, s->inter);
6702 task_queue(t); /* restore t to its place in the task list */
6703 return tv_remain(&now, &t->expire);
6704 }
6705 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
6706 s->result = -1; /* a real error */
6707 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006708 }
6709 }
willy tarreau08dedbe2005-12-18 01:13:48 +01006710 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006711 }
6712
6713 if (!s->result) { /* nothing done */
6714 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01006715 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6716 tv_delayfrom(&t->expire, &t->expire, s->inter);
6717 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006718 }
6719
6720 /* here, we have seen a failure */
willy tarreaucb406512006-05-18 00:52:35 +02006721 if (s->health > s->rise) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006722 s->health--; /* still good */
willy tarreaucb406512006-05-18 00:52:35 +02006723 s->failed_checks++;
6724 }
willy tarreau2812edc2006-05-04 12:09:37 +02006725 else
6726 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006727
6728 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01006729 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01006730 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6731 tv_delayfrom(&t->expire, &t->expire, s->inter);
6732 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006733 }
6734 else {
6735 //fprintf(stderr, "process_chk: 8\n");
6736 /* there was a test running */
6737 if (s->result > 0) { /* good server detected */
6738 //fprintf(stderr, "process_chk: 9\n");
6739 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01006740 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02006741 s->state |= SRV_RUNNING;
6742
willy tarreau535ae7a2005-12-17 12:58:00 +01006743 if (s->health == s->rise) {
willy tarreaubc2eda62006-05-04 15:16:23 +02006744 int xferred;
6745
willy tarreau62084d42006-03-24 18:57:41 +01006746 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02006747 recalc_server_map(s->proxy);
willy tarreaubc2eda62006-05-04 15:16:23 +02006748
6749 /* check if we can handle some connections queued at the proxy. We
6750 * will take as many as we can handle.
6751 */
willy tarreauf76e6ca2006-05-21 21:09:55 +02006752 for (xferred = 0; !s->maxconn || xferred < srv_dynamic_maxconn(s); xferred++) {
willy tarreaubc2eda62006-05-04 15:16:23 +02006753 struct session *sess;
6754 struct pendconn *p;
6755
6756 p = pendconn_from_px(s->proxy);
6757 if (!p)
6758 break;
6759 p->sess->srv = s;
6760 sess = p->sess;
6761 pendconn_free(p);
6762 task_wakeup(&rq, sess->task);
6763 }
6764
6765 sprintf(trash,
6766 "%sServer %s/%s is UP. %d active and %d backup servers online.%s"
6767 " %d sessions requeued, %d total in queue.\n",
6768 s->state & SRV_BACKUP ? "Backup " : "",
6769 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6770 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6771 xferred, s->nbpend);
6772
6773 Warning("%s", trash);
6774 send_log(s->proxy, LOG_NOTICE, "%s", trash);
willy tarreau535ae7a2005-12-17 12:58:00 +01006775 }
willy tarreauef900ab2005-12-17 12:52:52 +01006776
willy tarreaue47c8d72005-12-17 12:55:52 +01006777 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006778 }
willy tarreauef900ab2005-12-17 12:52:52 +01006779 s->curfd = -1; /* no check running anymore */
6780 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006781 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006782 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6783 tv_delayfrom(&t->expire, &t->expire, s->inter);
6784 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006785 }
6786 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
6787 //fprintf(stderr, "process_chk: 10\n");
6788 /* failure or timeout detected */
willy tarreaucb406512006-05-18 00:52:35 +02006789 if (s->health > s->rise) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006790 s->health--; /* still good */
willy tarreaucb406512006-05-18 00:52:35 +02006791 s->failed_checks++;
6792 }
willy tarreau2812edc2006-05-04 12:09:37 +02006793 else
6794 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006795 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01006796 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006797 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006798 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6799 tv_delayfrom(&t->expire, &t->expire, s->inter);
6800 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006801 }
6802 /* if result is 0 and there's no timeout, we have to wait again */
6803 }
6804 //fprintf(stderr, "process_chk: 11\n");
6805 s->result = 0;
6806 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006807 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01006808}
6809
6810
willy tarreau5cbea6f2005-12-17 12:48:26 +01006811
willy tarreau59a6cc22006-05-12 01:29:08 +02006812/*
6813 * Manages a server's connection queue. If woken up, will try to dequeue as
6814 * many pending sessions as possible, and wake them up. The task has nothing
6815 * else to do, so it always returns TIME_ETERNITY.
6816 */
6817int process_srv_queue(struct task *t) {
6818 struct server *s = (struct server*)t->context;
6819 struct proxy *p = s->proxy;
6820 int xferred;
6821
6822 /* First, check if we can handle some connections queued at the proxy. We
6823 * will take as many as we can handle.
6824 */
willy tarreauf76e6ca2006-05-21 21:09:55 +02006825 for (xferred = 0; s->cur_sess + xferred < srv_dynamic_maxconn(s); xferred++) {
willy tarreau59a6cc22006-05-12 01:29:08 +02006826 struct session *sess;
6827
6828 sess = pendconn_get_next_sess(s, p);
6829 if (sess == NULL)
6830 break;
6831 task_wakeup(&rq, sess->task);
6832 }
6833
6834 return TIME_ETERNITY;
6835}
6836
willy tarreau0f7af912005-12-17 12:21:26 +01006837#if STATTIME > 0
6838int stats(void);
6839#endif
6840
6841/*
willy tarreau1c2ad212005-12-18 01:11:29 +01006842 * This does 4 things :
6843 * - wake up all expired tasks
6844 * - call all runnable tasks
6845 * - call maintain_proxies() to enable/disable the listeners
6846 * - return the delay till next event in ms, -1 = wait indefinitely
6847 * Note: this part should be rewritten with the O(ln(n)) scheduler.
6848 *
willy tarreau0f7af912005-12-17 12:21:26 +01006849 */
6850
willy tarreau1c2ad212005-12-18 01:11:29 +01006851int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01006852 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01006853 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006854 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01006855
willy tarreaub952e1d2005-12-18 01:31:20 +01006856 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01006857
willy tarreau1c2ad212005-12-18 01:11:29 +01006858 /* look for expired tasks and add them to the run queue.
6859 */
willy tarreau5e698ef2006-05-02 14:51:00 +02006860 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6861 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau1c2ad212005-12-18 01:11:29 +01006862 tnext = t->next;
6863 if (t->state & TASK_RUNNING)
6864 continue;
6865
willy tarreaub952e1d2005-12-18 01:31:20 +01006866 if (tv_iseternity(&t->expire))
6867 continue;
6868
willy tarreau1c2ad212005-12-18 01:11:29 +01006869 /* wakeup expired entries. It doesn't matter if they are
6870 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01006871 */
willy tarreaub952e1d2005-12-18 01:31:20 +01006872 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006873 task_wakeup(&rq, t);
6874 }
6875 else {
6876 /* first non-runnable task. Use its expiration date as an upper bound */
6877 int temp_time = tv_remain(&now, &t->expire);
6878 if (temp_time)
6879 next_time = temp_time;
6880 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006881 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006882 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006883
willy tarreau1c2ad212005-12-18 01:11:29 +01006884 /* process each task in the run queue now. Each task may be deleted
willy tarreau7feab592006-04-22 15:13:16 +02006885 * since we only use the run queue's head. Note that any task can be
6886 * woken up by any other task and it will be processed immediately
6887 * after as it will be queued on the run queue's head.
willy tarreau1c2ad212005-12-18 01:11:29 +01006888 */
willy tarreau7feab592006-04-22 15:13:16 +02006889 while ((t = rq) != NULL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006890 int temp_time;
willy tarreau7feab592006-04-22 15:13:16 +02006891
willy tarreau1c2ad212005-12-18 01:11:29 +01006892 task_sleep(&rq, t);
6893 temp_time = t->process(t);
6894 next_time = MINTIME(temp_time, next_time);
6895 }
6896
6897 /* maintain all proxies in a consistent state. This should quickly become a task */
6898 time2 = maintain_proxies();
6899 return MINTIME(time2, next_time);
6900}
6901
6902
6903#if defined(ENABLE_EPOLL)
6904
6905/*
6906 * Main epoll() loop.
6907 */
6908
6909/* does 3 actions :
6910 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6911 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6912 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6913 *
6914 * returns 0 if initialization failed, !0 otherwise.
6915 */
6916
6917int epoll_loop(int action) {
6918 int next_time;
6919 int status;
6920 int fd;
6921
6922 int fds, count;
6923 int pr, pw, sr, sw;
6924 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
6925 struct epoll_event ev;
6926
6927 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01006928 static struct epoll_event *epoll_events = NULL;
6929 static int epoll_fd;
6930
6931 if (action == POLL_LOOP_ACTION_INIT) {
6932 epoll_fd = epoll_create(global.maxsock + 1);
6933 if (epoll_fd < 0)
6934 return 0;
6935 else {
6936 epoll_events = (struct epoll_event*)
6937 calloc(1, sizeof(struct epoll_event) * global.maxsock);
6938 PrevReadEvent = (fd_set *)
6939 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6940 PrevWriteEvent = (fd_set *)
6941 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006942 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006943 return 1;
6944 }
6945 else if (action == POLL_LOOP_ACTION_CLEAN) {
6946 if (PrevWriteEvent) free(PrevWriteEvent);
6947 if (PrevReadEvent) free(PrevReadEvent);
6948 if (epoll_events) free(epoll_events);
6949 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01006950 epoll_fd = 0;
6951 return 1;
6952 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006953
willy tarreau1c2ad212005-12-18 01:11:29 +01006954 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006955
willy tarreau1c2ad212005-12-18 01:11:29 +01006956 tv_now(&now);
6957
6958 while (1) {
6959 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01006960
6961 /* stop when there's no connection left and we don't allow them anymore */
6962 if (!actconn && listeners == 0)
6963 break;
6964
willy tarreau0f7af912005-12-17 12:21:26 +01006965#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01006966 {
6967 int time2;
6968 time2 = stats();
6969 next_time = MINTIME(time2, next_time);
6970 }
willy tarreau0f7af912005-12-17 12:21:26 +01006971#endif
6972
willy tarreau1c2ad212005-12-18 01:11:29 +01006973 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6974
6975 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
6976 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
6977
6978 if ((ro^rn) | (wo^wn)) {
6979 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6980#define FDSETS_ARE_INT_ALIGNED
6981#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01006982
willy tarreauad90a0c2005-12-18 01:09:15 +01006983#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6984#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01006985 pr = (ro >> count) & 1;
6986 pw = (wo >> count) & 1;
6987 sr = (rn >> count) & 1;
6988 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01006989#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006990 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
6991 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
6992 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6993 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01006994#endif
6995#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006996 pr = FD_ISSET(fd, PrevReadEvent);
6997 pw = FD_ISSET(fd, PrevWriteEvent);
6998 sr = FD_ISSET(fd, StaticReadEvent);
6999 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01007000#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01007001 if (!((sr^pr) | (sw^pw)))
7002 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01007003
willy tarreau1c2ad212005-12-18 01:11:29 +01007004 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
7005 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01007006
willy tarreaub952e1d2005-12-18 01:31:20 +01007007#ifdef EPOLL_CTL_MOD_WORKAROUND
7008 /* I encountered a rarely reproducible problem with
7009 * EPOLL_CTL_MOD where a modified FD (systematically
7010 * the one in epoll_events[0], fd#7) would sometimes
7011 * be set EPOLL_OUT while asked for a read ! This is
7012 * with the 2.4 epoll patch. The workaround is to
7013 * delete then recreate in case of modification.
7014 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
7015 * nor RHEL kernels.
7016 */
7017
7018 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
7019 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
7020
7021 if ((sr | sw))
7022 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
7023#else
willy tarreau1c2ad212005-12-18 01:11:29 +01007024 if ((pr | pw)) {
7025 /* the file-descriptor already exists... */
7026 if ((sr | sw)) {
7027 /* ...and it will still exist */
7028 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
7029 // perror("epoll_ctl(MOD)");
7030 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01007031 }
7032 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01007033 /* ...and it will be removed */
7034 if (fdtab[fd].state != FD_STCLOSE &&
7035 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
7036 // perror("epoll_ctl(DEL)");
7037 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01007038 }
7039 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007040 } else {
7041 /* the file-descriptor did not exist, let's add it */
7042 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
7043 // perror("epoll_ctl(ADD)");
7044 // exit(1);
7045 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007046 }
willy tarreaub952e1d2005-12-18 01:31:20 +01007047#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01007048 }
7049 ((int*)PrevReadEvent)[fds] = rn;
7050 ((int*)PrevWriteEvent)[fds] = wn;
7051 }
7052 }
7053
7054 /* now let's wait for events */
7055 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
7056 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01007057
willy tarreau1c2ad212005-12-18 01:11:29 +01007058 for (count = 0; count < status; count++) {
7059 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01007060
7061 if (FD_ISSET(fd, StaticReadEvent)) {
7062 if (fdtab[fd].state == FD_STCLOSE)
7063 continue;
7064 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
7065 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007066 }
willy tarreau05be12b2006-03-19 19:35:00 +01007067
7068 if (FD_ISSET(fd, StaticWriteEvent)) {
7069 if (fdtab[fd].state == FD_STCLOSE)
7070 continue;
7071 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
7072 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007073 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007074 }
7075 }
7076 return 1;
7077}
7078#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01007079
willy tarreauad90a0c2005-12-18 01:09:15 +01007080
willy tarreau5cbea6f2005-12-17 12:48:26 +01007081
willy tarreau1c2ad212005-12-18 01:11:29 +01007082#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01007083
willy tarreau1c2ad212005-12-18 01:11:29 +01007084/*
7085 * Main poll() loop.
7086 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007087
willy tarreau1c2ad212005-12-18 01:11:29 +01007088/* does 3 actions :
7089 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
7090 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
7091 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
7092 *
7093 * returns 0 if initialization failed, !0 otherwise.
7094 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007095
willy tarreau1c2ad212005-12-18 01:11:29 +01007096int poll_loop(int action) {
7097 int next_time;
7098 int status;
7099 int fd, nbfd;
7100
7101 int fds, count;
7102 int sr, sw;
7103 unsigned rn, wn; /* read new, write new */
7104
7105 /* private data */
7106 static struct pollfd *poll_events = NULL;
7107
7108 if (action == POLL_LOOP_ACTION_INIT) {
7109 poll_events = (struct pollfd*)
7110 calloc(1, sizeof(struct pollfd) * global.maxsock);
7111 return 1;
7112 }
7113 else if (action == POLL_LOOP_ACTION_CLEAN) {
7114 if (poll_events)
7115 free(poll_events);
7116 return 1;
7117 }
7118
7119 /* OK, it's POLL_LOOP_ACTION_RUN */
7120
7121 tv_now(&now);
7122
7123 while (1) {
7124 next_time = process_runnable_tasks();
7125
7126 /* stop when there's no connection left and we don't allow them anymore */
7127 if (!actconn && listeners == 0)
7128 break;
7129
7130#if STATTIME > 0
7131 {
7132 int time2;
7133 time2 = stats();
7134 next_time = MINTIME(time2, next_time);
7135 }
7136#endif
7137
7138
7139 nbfd = 0;
7140 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
7141
7142 rn = ((int*)StaticReadEvent)[fds];
7143 wn = ((int*)StaticWriteEvent)[fds];
7144
7145 if ((rn|wn)) {
7146 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
7147#define FDSETS_ARE_INT_ALIGNED
7148#ifdef FDSETS_ARE_INT_ALIGNED
7149
7150#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
7151#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
7152 sr = (rn >> count) & 1;
7153 sw = (wn >> count) & 1;
7154#else
7155 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
7156 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
7157#endif
7158#else
7159 sr = FD_ISSET(fd, StaticReadEvent);
7160 sw = FD_ISSET(fd, StaticWriteEvent);
7161#endif
7162 if ((sr|sw)) {
7163 poll_events[nbfd].fd = fd;
7164 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
7165 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01007166 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007167 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007168 }
7169 }
7170
7171 /* now let's wait for events */
7172 status = poll(poll_events, nbfd, next_time);
7173 tv_now(&now);
7174
7175 for (count = 0; status > 0 && count < nbfd; count++) {
7176 fd = poll_events[count].fd;
7177
willy tarreau606788e2006-05-21 16:26:20 +02007178 if (!(poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP )))
willy tarreau1c2ad212005-12-18 01:11:29 +01007179 continue;
7180
7181 /* ok, we found one active fd */
7182 status--;
7183
willy tarreau05be12b2006-03-19 19:35:00 +01007184 if (FD_ISSET(fd, StaticReadEvent)) {
7185 if (fdtab[fd].state == FD_STCLOSE)
7186 continue;
7187 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
7188 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007189 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007190
willy tarreau05be12b2006-03-19 19:35:00 +01007191 if (FD_ISSET(fd, StaticWriteEvent)) {
7192 if (fdtab[fd].state == FD_STCLOSE)
7193 continue;
7194 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
7195 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007196 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007197 }
7198 }
7199 return 1;
7200}
willy tarreauad90a0c2005-12-18 01:09:15 +01007201#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01007202
willy tarreauad90a0c2005-12-18 01:09:15 +01007203
willy tarreauad90a0c2005-12-18 01:09:15 +01007204
willy tarreau1c2ad212005-12-18 01:11:29 +01007205/*
7206 * Main select() loop.
7207 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007208
willy tarreau1c2ad212005-12-18 01:11:29 +01007209/* does 3 actions :
7210 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
7211 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
7212 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
7213 *
7214 * returns 0 if initialization failed, !0 otherwise.
7215 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007216
willy tarreauad90a0c2005-12-18 01:09:15 +01007217
willy tarreau1c2ad212005-12-18 01:11:29 +01007218int select_loop(int action) {
7219 int next_time;
7220 int status;
7221 int fd,i;
7222 struct timeval delta;
7223 int readnotnull, writenotnull;
7224 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01007225
willy tarreau1c2ad212005-12-18 01:11:29 +01007226 if (action == POLL_LOOP_ACTION_INIT) {
7227 ReadEvent = (fd_set *)
7228 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
7229 WriteEvent = (fd_set *)
7230 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
7231 return 1;
7232 }
7233 else if (action == POLL_LOOP_ACTION_CLEAN) {
7234 if (WriteEvent) free(WriteEvent);
7235 if (ReadEvent) free(ReadEvent);
7236 return 1;
7237 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007238
willy tarreau1c2ad212005-12-18 01:11:29 +01007239 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01007240
willy tarreau1c2ad212005-12-18 01:11:29 +01007241 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01007242
willy tarreau1c2ad212005-12-18 01:11:29 +01007243 while (1) {
7244 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01007245
willy tarreau1c2ad212005-12-18 01:11:29 +01007246 /* stop when there's no connection left and we don't allow them anymore */
7247 if (!actconn && listeners == 0)
7248 break;
7249
7250#if STATTIME > 0
7251 {
7252 int time2;
7253 time2 = stats();
7254 next_time = MINTIME(time2, next_time);
7255 }
7256#endif
7257
willy tarreau1c2ad212005-12-18 01:11:29 +01007258 if (next_time > 0) { /* FIXME */
7259 /* Convert to timeval */
7260 /* to avoid eventual select loops due to timer precision */
7261 next_time += SCHEDULER_RESOLUTION;
7262 delta.tv_sec = next_time / 1000;
7263 delta.tv_usec = (next_time % 1000) * 1000;
7264 }
7265 else if (next_time == 0) { /* allow select to return immediately when needed */
7266 delta.tv_sec = delta.tv_usec = 0;
7267 }
7268
7269
7270 /* let's restore fdset state */
7271
7272 readnotnull = 0; writenotnull = 0;
7273 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
7274 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
7275 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
7276 }
7277
7278 // /* just a verification code, needs to be removed for performance */
7279 // for (i=0; i<maxfd; i++) {
7280 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
7281 // abort();
7282 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
7283 // abort();
7284 //
7285 // }
7286
7287 status = select(maxfd,
7288 readnotnull ? ReadEvent : NULL,
7289 writenotnull ? WriteEvent : NULL,
7290 NULL,
7291 (next_time >= 0) ? &delta : NULL);
7292
7293 /* this is an experiment on the separation of the select work */
7294 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
7295 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
7296
7297 tv_now(&now);
7298
7299 if (status > 0) { /* must proceed with events */
7300
7301 int fds;
7302 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01007303
willy tarreau1c2ad212005-12-18 01:11:29 +01007304 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
7305 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
7306 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
7307
7308 /* if we specify read first, the accepts and zero reads will be
7309 * seen first. Moreover, system buffers will be flushed faster.
7310 */
willy tarreau05be12b2006-03-19 19:35:00 +01007311 if (FD_ISSET(fd, ReadEvent)) {
7312 if (fdtab[fd].state == FD_STCLOSE)
7313 continue;
7314 fdtab[fd].read(fd);
7315 }
willy tarreau64a3cc32005-12-18 01:13:11 +01007316
willy tarreau05be12b2006-03-19 19:35:00 +01007317 if (FD_ISSET(fd, WriteEvent)) {
7318 if (fdtab[fd].state == FD_STCLOSE)
7319 continue;
7320 fdtab[fd].write(fd);
7321 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007322 }
7323 }
7324 else {
7325 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01007326 }
willy tarreau0f7af912005-12-17 12:21:26 +01007327 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007328 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01007329}
7330
7331
7332#if STATTIME > 0
7333/*
7334 * Display proxy statistics regularly. It is designed to be called from the
7335 * select_loop().
7336 */
7337int stats(void) {
7338 static int lines;
7339 static struct timeval nextevt;
7340 static struct timeval lastevt;
7341 static struct timeval starttime = {0,0};
7342 unsigned long totaltime, deltatime;
7343 int ret;
7344
willy tarreau750a4722005-12-17 13:21:24 +01007345 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01007346 deltatime = (tv_diff(&lastevt, &now)?:1);
7347 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01007348
willy tarreau9fe663a2005-12-17 13:02:59 +01007349 if (global.mode & MODE_STATS) {
7350 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007351 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007352 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
7353 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007354 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01007355 actconn, totalconn,
7356 stats_tsk_new, stats_tsk_good,
7357 stats_tsk_left, stats_tsk_right,
7358 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
7359 }
7360 }
7361
7362 tv_delayfrom(&nextevt, &now, STATTIME);
7363
7364 lastevt=now;
7365 }
7366 ret = tv_remain(&now, &nextevt);
7367 return ret;
7368}
7369#endif
7370
7371
7372/*
7373 * this function enables proxies when there are enough free sessions,
7374 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01007375 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01007376 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01007377 */
7378static int maintain_proxies(void) {
7379 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01007380 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007381 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01007382
7383 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01007384 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01007385
7386 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01007387 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01007388 while (p) {
7389 if (p->nbconn < p->maxconn) {
7390 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007391 for (l = p->listen; l != NULL; l = l->next) {
7392 FD_SET(l->fd, StaticReadEvent);
7393 }
willy tarreau0f7af912005-12-17 12:21:26 +01007394 p->state = PR_STRUN;
7395 }
7396 }
7397 else {
7398 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007399 for (l = p->listen; l != NULL; l = l->next) {
7400 FD_CLR(l->fd, StaticReadEvent);
7401 }
willy tarreau0f7af912005-12-17 12:21:26 +01007402 p->state = PR_STIDLE;
7403 }
7404 }
7405 p = p->next;
7406 }
7407 }
7408 else { /* block all proxies */
7409 while (p) {
7410 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007411 for (l = p->listen; l != NULL; l = l->next) {
7412 FD_CLR(l->fd, StaticReadEvent);
7413 }
willy tarreau0f7af912005-12-17 12:21:26 +01007414 p->state = PR_STIDLE;
7415 }
7416 p = p->next;
7417 }
7418 }
7419
willy tarreau5cbea6f2005-12-17 12:48:26 +01007420 if (stopping) {
7421 p = proxy;
7422 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007423 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007424 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01007425 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007426 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01007427 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01007428 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01007429
willy tarreaua41a8b42005-12-17 14:02:24 +01007430 for (l = p->listen; l != NULL; l = l->next) {
7431 fd_delete(l->fd);
7432 listeners--;
7433 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007434 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007435 }
7436 else {
7437 tleft = MINTIME(t, tleft);
7438 }
7439 }
7440 p = p->next;
7441 }
7442 }
7443 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01007444}
7445
7446/*
7447 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01007448 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
7449 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01007450 */
7451static void soft_stop(void) {
7452 struct proxy *p;
7453
7454 stopping = 1;
7455 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007456 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01007457 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01007458 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01007459 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01007460 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01007461 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01007462 }
willy tarreau0f7af912005-12-17 12:21:26 +01007463 p = p->next;
7464 }
7465}
7466
willy tarreaufac1a862006-05-21 10:20:28 +02007467/*
7468 * Linux unbinds the listen socket after a SHUT_RD, and ignores SHUT_WR.
7469 * Solaris refuses either shutdown().
7470 * OpenBSD ignores SHUT_RD but closes upon SHUT_WR and refuses to rebind.
7471 * So a common validation path involves SHUT_WR && listen && SHUT_RD.
7472 * If disabling at least one listener returns an error, then the proxy
7473 * state is set to PR_STERROR because we don't know how to resume from this.
7474 */
willy tarreaudbd3bef2006-01-20 19:35:18 +01007475static void pause_proxy(struct proxy *p) {
7476 struct listener *l;
7477 for (l = p->listen; l != NULL; l = l->next) {
willy tarreaufac1a862006-05-21 10:20:28 +02007478 if (shutdown(l->fd, SHUT_WR) == 0 && listen(l->fd, p->maxconn) == 0 &&
7479 shutdown(l->fd, SHUT_RD) == 0) {
Willy TARREAU007aa462006-05-14 09:55:23 +02007480 FD_CLR(l->fd, StaticReadEvent);
willy tarreaufac1a862006-05-21 10:20:28 +02007481 if (p->state != PR_STERROR)
7482 p->state = PR_STPAUSED;
Willy TARREAU007aa462006-05-14 09:55:23 +02007483 }
willy tarreaufac1a862006-05-21 10:20:28 +02007484 else
7485 p->state = PR_STERROR;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007486 }
7487}
7488
7489/*
7490 * This function temporarily disables listening so that another new instance
7491 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01007492 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01007493 * the proxy, or a SIGTTIN can be sent to listen again.
7494 */
7495static void pause_proxies(void) {
Willy TARREAU007aa462006-05-14 09:55:23 +02007496 int err;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007497 struct proxy *p;
7498
Willy TARREAU007aa462006-05-14 09:55:23 +02007499 err = 0;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007500 p = proxy;
7501 tv_now(&now); /* else, the old time before select will be used */
7502 while (p) {
willy tarreaufac1a862006-05-21 10:20:28 +02007503 if (p->state != PR_STERROR && p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007504 Warning("Pausing proxy %s.\n", p->id);
7505 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
7506 pause_proxy(p);
Willy TARREAU007aa462006-05-14 09:55:23 +02007507 if (p->state != PR_STPAUSED) {
7508 err |= 1;
7509 Warning("Proxy %s failed to enter pause mode.\n", p->id);
7510 send_log(p, LOG_WARNING, "Proxy %s failed to enter pause mode.\n", p->id);
7511 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007512 }
7513 p = p->next;
7514 }
Willy TARREAU007aa462006-05-14 09:55:23 +02007515 if (err) {
7516 Warning("Some proxies refused to pause, performing soft stop now.\n");
7517 send_log(p, LOG_WARNING, "Some proxies refused to pause, performing soft stop now.\n");
7518 soft_stop();
7519 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007520}
7521
7522
7523/*
7524 * This function reactivates listening. This can be used after a call to
7525 * sig_pause(), for example when a new instance has failed starting up.
7526 * It is designed to be called upon reception of a SIGTTIN.
7527 */
7528static void listen_proxies(void) {
7529 struct proxy *p;
7530 struct listener *l;
7531
7532 p = proxy;
7533 tv_now(&now); /* else, the old time before select will be used */
7534 while (p) {
7535 if (p->state == PR_STPAUSED) {
7536 Warning("Enabling proxy %s.\n", p->id);
7537 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
7538
7539 for (l = p->listen; l != NULL; l = l->next) {
7540 if (listen(l->fd, p->maxconn) == 0) {
7541 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
7542 FD_SET(l->fd, StaticReadEvent);
7543 p->state = PR_STRUN;
7544 }
7545 else
7546 p->state = PR_STIDLE;
7547 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01007548 int port;
7549
7550 if (l->addr.ss_family == AF_INET6)
7551 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
7552 else
7553 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
7554
willy tarreaudbd3bef2006-01-20 19:35:18 +01007555 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01007556 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01007557 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01007558 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01007559 /* Another port might have been enabled. Let's stop everything. */
7560 pause_proxy(p);
7561 break;
7562 }
7563 }
7564 }
7565 p = p->next;
7566 }
7567}
7568
7569
willy tarreau0f7af912005-12-17 12:21:26 +01007570/*
7571 * upon SIGUSR1, let's have a soft stop.
7572 */
7573void sig_soft_stop(int sig) {
7574 soft_stop();
7575 signal(sig, SIG_IGN);
7576}
7577
willy tarreaudbd3bef2006-01-20 19:35:18 +01007578/*
7579 * upon SIGTTOU, we pause everything
7580 */
7581void sig_pause(int sig) {
7582 pause_proxies();
7583 signal(sig, sig_pause);
7584}
willy tarreau0f7af912005-12-17 12:21:26 +01007585
willy tarreau8337c6b2005-12-17 13:41:01 +01007586/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01007587 * upon SIGTTIN, let's have a soft stop.
7588 */
7589void sig_listen(int sig) {
7590 listen_proxies();
7591 signal(sig, sig_listen);
7592}
7593
7594/*
willy tarreau8337c6b2005-12-17 13:41:01 +01007595 * this function dumps every server's state when the process receives SIGHUP.
7596 */
7597void sig_dump_state(int sig) {
7598 struct proxy *p = proxy;
7599
7600 Warning("SIGHUP received, dumping servers states.\n");
7601 while (p) {
7602 struct server *s = p->srv;
7603
willy tarreau4632c212006-05-02 23:32:51 +02007604 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01007605 while (s) {
willy tarreau4632c212006-05-02 23:32:51 +02007606 snprintf(trash, sizeof(trash),
7607 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %d tot.",
7608 p->id, s->id,
7609 (s->state & SRV_RUNNING) ? "UP" : "DOWN",
7610 s->cur_sess, s->nbpend, s->cum_sess);
willy tarreau14b4d432006-04-07 18:23:29 +02007611 Warning("%s\n", trash);
7612 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01007613 s = s->next;
7614 }
willy tarreaudd07e972005-12-18 00:48:48 +01007615
willy tarreau62084d42006-03-24 18:57:41 +01007616 if (p->srv_act == 0) {
willy tarreau4632c212006-05-02 23:32:51 +02007617 snprintf(trash, sizeof(trash),
7618 "SIGHUP: Proxy %s %s ! Conn: %d act, %d pend (%d unass), %d tot.",
7619 p->id,
7620 (p->srv_bck) ? "is running on backup servers" : "has no server available",
7621 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02007622 } else {
7623 snprintf(trash, sizeof(trash),
willy tarreau4632c212006-05-02 23:32:51 +02007624 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
7625 " Conn: %d act, %d pend (%d unass), %d tot.",
7626 p->id, p->srv_act, p->srv_bck,
7627 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02007628 }
7629 Warning("%s\n", trash);
7630 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01007631
willy tarreau8337c6b2005-12-17 13:41:01 +01007632 p = p->next;
7633 }
7634 signal(sig, sig_dump_state);
7635}
7636
willy tarreau0f7af912005-12-17 12:21:26 +01007637void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007638 struct task *t, *tnext;
7639 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01007640
willy tarreau5e698ef2006-05-02 14:51:00 +02007641 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
7642 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007643 tnext = t->next;
7644 s = t->context;
7645 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
7646 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
7647 "req=%d, rep=%d, clifd=%d\n",
7648 s, tv_remain(&now, &t->expire),
7649 s->cli_state,
7650 s->srv_state,
7651 FD_ISSET(s->cli_fd, StaticReadEvent),
7652 FD_ISSET(s->cli_fd, StaticWriteEvent),
7653 FD_ISSET(s->srv_fd, StaticReadEvent),
7654 FD_ISSET(s->srv_fd, StaticWriteEvent),
7655 s->req->l, s->rep?s->rep->l:0, s->cli_fd
7656 );
willy tarreau0f7af912005-12-17 12:21:26 +01007657 }
willy tarreau12350152005-12-18 01:03:27 +01007658}
7659
willy tarreau64a3cc32005-12-18 01:13:11 +01007660#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01007661static void fast_stop(void)
7662{
7663 struct proxy *p;
7664 p = proxy;
7665 while (p) {
7666 p->grace = 0;
7667 p = p->next;
7668 }
7669 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01007670}
7671
willy tarreau12350152005-12-18 01:03:27 +01007672void sig_int(int sig) {
7673 /* This would normally be a hard stop,
7674 but we want to be sure about deallocation,
7675 and so on, so we do a soft stop with
7676 0 GRACE time
7677 */
7678 fast_stop();
7679 /* If we are killed twice, we decide to die*/
7680 signal(sig, SIG_DFL);
7681}
7682
7683void sig_term(int sig) {
7684 /* This would normally be a hard stop,
7685 but we want to be sure about deallocation,
7686 and so on, so we do a soft stop with
7687 0 GRACE time
7688 */
7689 fast_stop();
7690 /* If we are killed twice, we decide to die*/
7691 signal(sig, SIG_DFL);
7692}
willy tarreau64a3cc32005-12-18 01:13:11 +01007693#endif
willy tarreau12350152005-12-18 01:03:27 +01007694
willy tarreauc1f47532005-12-18 01:08:26 +01007695/* returns the pointer to an error in the replacement string, or NULL if OK */
7696char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01007697 struct hdr_exp *exp;
7698
willy tarreauc1f47532005-12-18 01:08:26 +01007699 if (replace != NULL) {
7700 char *err;
7701 err = check_replace_string(replace);
7702 if (err)
7703 return err;
7704 }
7705
willy tarreaue39cd132005-12-17 13:00:18 +01007706 while (*head != NULL)
7707 head = &(*head)->next;
7708
7709 exp = calloc(1, sizeof(struct hdr_exp));
7710
7711 exp->preg = preg;
7712 exp->replace = replace;
7713 exp->action = action;
7714 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01007715
7716 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007717}
7718
willy tarreau9fe663a2005-12-17 13:02:59 +01007719
willy tarreau0f7af912005-12-17 12:21:26 +01007720/*
willy tarreau9fe663a2005-12-17 13:02:59 +01007721 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01007722 */
willy tarreau9fe663a2005-12-17 13:02:59 +01007723int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01007724
willy tarreau9fe663a2005-12-17 13:02:59 +01007725 if (!strcmp(args[0], "global")) { /* new section */
7726 /* no option, nothing special to do */
7727 return 0;
7728 }
7729 else if (!strcmp(args[0], "daemon")) {
7730 global.mode |= MODE_DAEMON;
7731 }
7732 else if (!strcmp(args[0], "debug")) {
7733 global.mode |= MODE_DEBUG;
7734 }
willy tarreau64a3cc32005-12-18 01:13:11 +01007735 else if (!strcmp(args[0], "noepoll")) {
7736 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
7737 }
7738 else if (!strcmp(args[0], "nopoll")) {
7739 cfg_polling_mechanism &= ~POLL_USE_POLL;
7740 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007741 else if (!strcmp(args[0], "quiet")) {
7742 global.mode |= MODE_QUIET;
7743 }
7744 else if (!strcmp(args[0], "stats")) {
7745 global.mode |= MODE_STATS;
7746 }
7747 else if (!strcmp(args[0], "uid")) {
7748 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007749 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007750 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007751 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007752 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007753 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007754 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007755 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007756 global.uid = atol(args[1]);
7757 }
7758 else if (!strcmp(args[0], "gid")) {
7759 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007760 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007761 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007762 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007763 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007764 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007765 return -1;
7766 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007767 global.gid = atol(args[1]);
7768 }
7769 else if (!strcmp(args[0], "nbproc")) {
7770 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007771 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007772 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007773 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007774 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007775 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007776 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007777 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007778 global.nbproc = atol(args[1]);
7779 }
7780 else if (!strcmp(args[0], "maxconn")) {
7781 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007782 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007783 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007784 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007785 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007786 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007787 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007788 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007789 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01007790#ifdef SYSTEM_MAXCONN
7791 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
7792 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);
7793 global.maxconn = DEFAULT_MAXCONN;
7794 }
7795#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01007796 }
willy tarreaub1285d52005-12-18 01:20:14 +01007797 else if (!strcmp(args[0], "ulimit-n")) {
7798 if (global.rlimit_nofile != 0) {
7799 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7800 return 0;
7801 }
7802 if (*(args[1]) == 0) {
7803 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
7804 return -1;
7805 }
7806 global.rlimit_nofile = atol(args[1]);
7807 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007808 else if (!strcmp(args[0], "chroot")) {
7809 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007810 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007811 return 0;
7812 }
7813 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007814 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007815 return -1;
7816 }
7817 global.chroot = strdup(args[1]);
7818 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007819 else if (!strcmp(args[0], "pidfile")) {
7820 if (global.pidfile != NULL) {
7821 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7822 return 0;
7823 }
7824 if (*(args[1]) == 0) {
7825 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
7826 return -1;
7827 }
7828 global.pidfile = strdup(args[1]);
7829 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007830 else if (!strcmp(args[0], "log")) { /* syslog server address */
7831 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01007832 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007833
7834 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007835 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007836 return -1;
7837 }
7838
7839 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7840 if (!strcmp(log_facilities[facility], args[2]))
7841 break;
7842
7843 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007844 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007845 exit(1);
7846 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007847
7848 level = 7; /* max syslog level = debug */
7849 if (*(args[3])) {
7850 while (level >= 0 && strcmp(log_levels[level], args[3]))
7851 level--;
7852 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007853 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007854 exit(1);
7855 }
7856 }
7857
willy tarreau9fe663a2005-12-17 13:02:59 +01007858 sa = str2sa(args[1]);
7859 if (!sa->sin_port)
7860 sa->sin_port = htons(SYSLOG_PORT);
7861
7862 if (global.logfac1 == -1) {
7863 global.logsrv1 = *sa;
7864 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007865 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007866 }
7867 else if (global.logfac2 == -1) {
7868 global.logsrv2 = *sa;
7869 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007870 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007871 }
7872 else {
7873 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
7874 return -1;
7875 }
7876
7877 }
7878 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007879 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01007880 return -1;
7881 }
7882 return 0;
7883}
7884
7885
willy tarreaua41a8b42005-12-17 14:02:24 +01007886void init_default_instance() {
7887 memset(&defproxy, 0, sizeof(defproxy));
7888 defproxy.mode = PR_MODE_TCP;
7889 defproxy.state = PR_STNEW;
7890 defproxy.maxconn = cfg_maxpconn;
7891 defproxy.conn_retries = CONN_RETRIES;
7892 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
7893}
7894
willy tarreau9fe663a2005-12-17 13:02:59 +01007895/*
7896 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
7897 */
7898int cfg_parse_listen(char *file, int linenum, char **args) {
7899 static struct proxy *curproxy = NULL;
7900 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01007901 char *err;
willy tarreau12350152005-12-18 01:03:27 +01007902 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01007903
7904 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01007905 if (!*args[1]) {
7906 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
7907 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007908 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007909 return -1;
7910 }
7911
7912 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007913 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007914 return -1;
7915 }
willy tarreaudfece232006-05-02 00:19:57 +02007916
willy tarreau9fe663a2005-12-17 13:02:59 +01007917 curproxy->next = proxy;
7918 proxy = curproxy;
willy tarreaudfece232006-05-02 00:19:57 +02007919 LIST_INIT(&curproxy->pendconns);
7920
willy tarreau9fe663a2005-12-17 13:02:59 +01007921 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01007922
7923 /* parse the listener address if any */
7924 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007925 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007926 if (!curproxy->listen)
7927 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007928 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01007929 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007930
willy tarreau9fe663a2005-12-17 13:02:59 +01007931 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01007932 curproxy->state = defproxy.state;
7933 curproxy->maxconn = defproxy.maxconn;
7934 curproxy->conn_retries = defproxy.conn_retries;
7935 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007936
7937 if (defproxy.check_req)
7938 curproxy->check_req = strdup(defproxy.check_req);
7939 curproxy->check_len = defproxy.check_len;
7940
7941 if (defproxy.cookie_name)
7942 curproxy->cookie_name = strdup(defproxy.cookie_name);
7943 curproxy->cookie_len = defproxy.cookie_len;
7944
7945 if (defproxy.capture_name)
7946 curproxy->capture_name = strdup(defproxy.capture_name);
7947 curproxy->capture_namelen = defproxy.capture_namelen;
7948 curproxy->capture_len = defproxy.capture_len;
7949
7950 if (defproxy.errmsg.msg400)
7951 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
7952 curproxy->errmsg.len400 = defproxy.errmsg.len400;
7953
7954 if (defproxy.errmsg.msg403)
7955 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
7956 curproxy->errmsg.len403 = defproxy.errmsg.len403;
7957
7958 if (defproxy.errmsg.msg408)
7959 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
7960 curproxy->errmsg.len408 = defproxy.errmsg.len408;
7961
7962 if (defproxy.errmsg.msg500)
7963 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
7964 curproxy->errmsg.len500 = defproxy.errmsg.len500;
7965
7966 if (defproxy.errmsg.msg502)
7967 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
7968 curproxy->errmsg.len502 = defproxy.errmsg.len502;
7969
7970 if (defproxy.errmsg.msg503)
7971 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
7972 curproxy->errmsg.len503 = defproxy.errmsg.len503;
7973
7974 if (defproxy.errmsg.msg504)
7975 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
7976 curproxy->errmsg.len504 = defproxy.errmsg.len504;
7977
willy tarreaua41a8b42005-12-17 14:02:24 +01007978 curproxy->clitimeout = defproxy.clitimeout;
7979 curproxy->contimeout = defproxy.contimeout;
7980 curproxy->srvtimeout = defproxy.srvtimeout;
7981 curproxy->mode = defproxy.mode;
7982 curproxy->logfac1 = defproxy.logfac1;
7983 curproxy->logsrv1 = defproxy.logsrv1;
7984 curproxy->loglev1 = defproxy.loglev1;
7985 curproxy->logfac2 = defproxy.logfac2;
7986 curproxy->logsrv2 = defproxy.logsrv2;
7987 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01007988 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01007989 curproxy->grace = defproxy.grace;
willy tarreau1f431b52006-05-21 14:46:15 +02007990 curproxy->uri_auth = defproxy.uri_auth;
willy tarreaua41a8b42005-12-17 14:02:24 +01007991 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01007992 curproxy->mon_net = defproxy.mon_net;
7993 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01007994 return 0;
7995 }
7996 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007997 /* some variables may have already been initialized earlier */
7998 if (defproxy.check_req) free(defproxy.check_req);
7999 if (defproxy.cookie_name) free(defproxy.cookie_name);
8000 if (defproxy.capture_name) free(defproxy.capture_name);
8001 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
8002 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
8003 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
8004 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
8005 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
8006 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
8007 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
willy tarreau1f431b52006-05-21 14:46:15 +02008008 /* we cannot free uri_auth because it might already be used */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008009 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01008010 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01008011 return 0;
8012 }
8013 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008014 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01008015 return -1;
8016 }
8017
willy tarreaua41a8b42005-12-17 14:02:24 +01008018 if (!strcmp(args[0], "bind")) { /* new listen addresses */
8019 if (curproxy == &defproxy) {
8020 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8021 return -1;
8022 }
8023
8024 if (strchr(args[1], ':') == NULL) {
8025 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
8026 file, linenum, args[0]);
8027 return -1;
8028 }
8029 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01008030 if (!curproxy->listen)
8031 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008032 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01008033 return 0;
8034 }
willy tarreaub1285d52005-12-18 01:20:14 +01008035 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
8036 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
8037 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
8038 file, linenum, args[0]);
8039 return -1;
8040 }
8041 /* flush useless bits */
8042 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
8043 return 0;
8044 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008045 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01008046 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
8047 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
8048 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
8049 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008050 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008051 return -1;
8052 }
8053 }
8054 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01008055 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01008056 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008057 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
8058 curproxy->state = PR_STNEW;
8059 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008060 else if (!strcmp(args[0], "cookie")) { /* cookie name */
8061 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01008062// if (curproxy == &defproxy) {
8063// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8064// return -1;
8065// }
willy tarreaua41a8b42005-12-17 14:02:24 +01008066
willy tarreau9fe663a2005-12-17 13:02:59 +01008067 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008068// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
8069// file, linenum);
8070// return 0;
8071 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01008072 }
8073
8074 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008075 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
8076 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008077 return -1;
8078 }
8079 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008080 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01008081
8082 cur_arg = 2;
8083 while (*(args[cur_arg])) {
8084 if (!strcmp(args[cur_arg], "rewrite")) {
8085 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01008086 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008087 else if (!strcmp(args[cur_arg], "indirect")) {
8088 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01008089 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008090 else if (!strcmp(args[cur_arg], "insert")) {
8091 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01008092 }
willy tarreau240afa62005-12-17 13:14:35 +01008093 else if (!strcmp(args[cur_arg], "nocache")) {
8094 curproxy->options |= PR_O_COOK_NOC;
8095 }
willy tarreaucd878942005-12-17 13:27:43 +01008096 else if (!strcmp(args[cur_arg], "postonly")) {
8097 curproxy->options |= PR_O_COOK_POST;
8098 }
willy tarreau0174f312005-12-18 01:02:42 +01008099 else if (!strcmp(args[cur_arg], "prefix")) {
8100 curproxy->options |= PR_O_COOK_PFX;
8101 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008102 else {
willy tarreau0174f312005-12-18 01:02:42 +01008103 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008104 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01008105 return -1;
8106 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008107 cur_arg++;
8108 }
willy tarreau0174f312005-12-18 01:02:42 +01008109 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
8110 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
8111 file, linenum);
8112 return -1;
8113 }
8114
8115 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
8116 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01008117 file, linenum);
8118 return -1;
8119 }
willy tarreau12350152005-12-18 01:03:27 +01008120 }/* end else if (!strcmp(args[0], "cookie")) */
8121 else if (!strcmp(args[0], "appsession")) { /* cookie name */
8122// if (curproxy == &defproxy) {
8123// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8124// return -1;
8125// }
8126
8127 if (curproxy->appsession_name != NULL) {
8128// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
8129// file, linenum);
8130// return 0;
8131 free(curproxy->appsession_name);
8132 }
8133
8134 if (*(args[5]) == 0) {
8135 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
8136 file, linenum, args[0]);
8137 return -1;
8138 }
8139 have_appsession = 1;
8140 curproxy->appsession_name = strdup(args[1]);
8141 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
8142 curproxy->appsession_len = atoi(args[3]);
8143 curproxy->appsession_timeout = atoi(args[5]);
8144 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
8145 if (rc) {
8146 Alert("Error Init Appsession Hashtable.\n");
8147 return -1;
8148 }
8149 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01008150 else if (!strcmp(args[0], "capture")) {
8151 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
8152 // if (curproxy == &defproxy) {
8153 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8154 // return -1;
8155 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01008156
willy tarreau4302f492005-12-18 01:00:37 +01008157 if (curproxy->capture_name != NULL) {
8158 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
8159 // file, linenum, args[0]);
8160 // return 0;
8161 free(curproxy->capture_name);
8162 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008163
willy tarreau4302f492005-12-18 01:00:37 +01008164 if (*(args[4]) == 0) {
8165 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
8166 file, linenum, args[0]);
8167 return -1;
8168 }
8169 curproxy->capture_name = strdup(args[2]);
8170 curproxy->capture_namelen = strlen(curproxy->capture_name);
8171 curproxy->capture_len = atol(args[4]);
8172 if (curproxy->capture_len >= CAPTURE_LEN) {
8173 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
8174 file, linenum, CAPTURE_LEN - 1);
8175 curproxy->capture_len = CAPTURE_LEN - 1;
8176 }
8177 curproxy->to_log |= LW_COOKIE;
8178 }
8179 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
8180 struct cap_hdr *hdr;
8181
8182 if (curproxy == &defproxy) {
8183 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
8184 return -1;
8185 }
8186
8187 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
8188 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
8189 file, linenum, args[0], args[1]);
8190 return -1;
8191 }
8192
8193 hdr = calloc(sizeof(struct cap_hdr), 1);
8194 hdr->next = curproxy->req_cap;
8195 hdr->name = strdup(args[3]);
8196 hdr->namelen = strlen(args[3]);
8197 hdr->len = atol(args[5]);
8198 hdr->index = curproxy->nb_req_cap++;
8199 curproxy->req_cap = hdr;
8200 curproxy->to_log |= LW_REQHDR;
8201 }
8202 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
8203 struct cap_hdr *hdr;
8204
8205 if (curproxy == &defproxy) {
8206 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
8207 return -1;
8208 }
8209
8210 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
8211 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
8212 file, linenum, args[0], args[1]);
8213 return -1;
8214 }
8215 hdr = calloc(sizeof(struct cap_hdr), 1);
8216 hdr->next = curproxy->rsp_cap;
8217 hdr->name = strdup(args[3]);
8218 hdr->namelen = strlen(args[3]);
8219 hdr->len = atol(args[5]);
8220 hdr->index = curproxy->nb_rsp_cap++;
8221 curproxy->rsp_cap = hdr;
8222 curproxy->to_log |= LW_RSPHDR;
8223 }
8224 else {
8225 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008226 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008227 return -1;
8228 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008229 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008230 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008231 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008232 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008233 return 0;
8234 }
8235 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008236 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8237 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008238 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008239 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008240 curproxy->contimeout = atol(args[1]);
8241 }
8242 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008243 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008244 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
8245 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008246 return 0;
8247 }
8248 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008249 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8250 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008251 return -1;
8252 }
8253 curproxy->clitimeout = atol(args[1]);
8254 }
8255 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008256 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008257 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008258 return 0;
8259 }
8260 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008261 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8262 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01008263 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008264 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008265 curproxy->srvtimeout = atol(args[1]);
8266 }
8267 else if (!strcmp(args[0], "retries")) { /* connection retries */
8268 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008269 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
8270 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008271 return -1;
8272 }
8273 curproxy->conn_retries = atol(args[1]);
8274 }
willy tarreau9e138862006-05-14 23:06:28 +02008275 else if (!strcmp(args[0], "stats")) {
willy tarreau1f431b52006-05-21 14:46:15 +02008276 if (curproxy != &defproxy && curproxy->uri_auth == defproxy.uri_auth)
8277 curproxy->uri_auth = NULL; /* we must detach from the default config */
8278
willy tarreau9e138862006-05-14 23:06:28 +02008279 if (*(args[1]) == 0) {
willy tarreau1f431b52006-05-21 14:46:15 +02008280 Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'auth', 'scope' or 'enable'.\n", file, linenum, args[0]);
willy tarreau9e138862006-05-14 23:06:28 +02008281 return -1;
8282 } else if (!strcmp(args[1], "uri")) {
8283 if (*(args[2]) == 0) {
8284 Alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
8285 return -1;
8286 } else if (!stats_set_uri(&curproxy->uri_auth, args[2])) {
8287 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8288 return -1;
8289 }
8290 } else if (!strcmp(args[1], "realm")) {
8291 if (*(args[2]) == 0) {
8292 Alert("parsing [%s:%d] : 'realm' needs an realm name.\n", file, linenum);
8293 return -1;
8294 } else if (!stats_set_realm(&curproxy->uri_auth, args[2])) {
8295 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8296 return -1;
8297 }
8298 } else if (!strcmp(args[1], "auth")) {
8299 if (*(args[2]) == 0) {
8300 Alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
8301 return -1;
8302 } else if (!stats_add_auth(&curproxy->uri_auth, args[2])) {
8303 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8304 return -1;
8305 }
willy tarreau1f431b52006-05-21 14:46:15 +02008306 } else if (!strcmp(args[1], "scope")) {
8307 if (*(args[2]) == 0) {
8308 Alert("parsing [%s:%d] : 'scope' needs a proxy name.\n", file, linenum);
8309 return -1;
8310 } else if (!stats_add_scope(&curproxy->uri_auth, args[2])) {
8311 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8312 return -1;
8313 }
willy tarreau9e138862006-05-14 23:06:28 +02008314 } else if (!strcmp(args[1], "enable")) {
8315 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
8316 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8317 return -1;
8318 }
8319 } else {
8320 Alert("parsing [%s:%d] : unknown stats parameter '%s' (expects 'uri', 'realm', 'auth' or 'enable').\n",
8321 file, linenum, args[0]);
8322 return -1;
8323 }
8324 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008325 else if (!strcmp(args[0], "option")) {
8326 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008327 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008328 return -1;
8329 }
8330 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01008331 /* enable reconnections to dispatch */
8332 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01008333#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01008334 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01008335 /* enable transparent proxy connections */
8336 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01008337#endif
8338 else if (!strcmp(args[1], "keepalive"))
8339 /* enable keep-alive */
8340 curproxy->options |= PR_O_KEEPALIVE;
8341 else if (!strcmp(args[1], "forwardfor"))
8342 /* insert x-forwarded-for field */
8343 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01008344 else if (!strcmp(args[1], "logasap"))
8345 /* log as soon as possible, without waiting for the session to complete */
8346 curproxy->options |= PR_O_LOGASAP;
willy tarreau03a92de2006-05-21 18:26:53 +02008347 else if (!strcmp(args[1], "abortonclose"))
8348 /* abort connection if client closes during queue or connect() */
8349 curproxy->options |= PR_O_ABRT_CLOSE;
willy tarreau25c4ea52005-12-18 00:49:49 +01008350 else if (!strcmp(args[1], "httpclose"))
8351 /* force connection: close in both directions in HTTP mode */
8352 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01008353 else if (!strcmp(args[1], "forceclose"))
8354 /* force connection: close in both directions in HTTP mode and enforce end of session */
8355 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01008356 else if (!strcmp(args[1], "checkcache"))
8357 /* require examination of cacheability of the 'set-cookie' field */
8358 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01008359 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01008360 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01008361 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01008362 else if (!strcmp(args[1], "tcplog"))
8363 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01008364 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01008365 else if (!strcmp(args[1], "dontlognull")) {
8366 /* don't log empty requests */
8367 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008368 }
willy tarreaub952e1d2005-12-18 01:31:20 +01008369 else if (!strcmp(args[1], "tcpka")) {
8370 /* enable TCP keep-alives on client and server sessions */
8371 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
8372 }
8373 else if (!strcmp(args[1], "clitcpka")) {
8374 /* enable TCP keep-alives on client sessions */
8375 curproxy->options |= PR_O_TCP_CLI_KA;
8376 }
8377 else if (!strcmp(args[1], "srvtcpka")) {
8378 /* enable TCP keep-alives on server sessions */
8379 curproxy->options |= PR_O_TCP_SRV_KA;
8380 }
Willy TARREAU3481c462006-03-01 22:37:57 +01008381 else if (!strcmp(args[1], "allbackups")) {
8382 /* Use all backup servers simultaneously */
8383 curproxy->options |= PR_O_USE_ALL_BK;
8384 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008385 else if (!strcmp(args[1], "httpchk")) {
8386 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008387 if (curproxy->check_req != NULL) {
8388 free(curproxy->check_req);
8389 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008390 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01008391 if (!*args[2]) { /* no argument */
8392 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
8393 curproxy->check_len = strlen(DEF_CHECK_REQ);
8394 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01008395 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
8396 curproxy->check_req = (char *)malloc(reqlen);
8397 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
8398 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008399 } else { /* more arguments : METHOD URI [HTTP_VER] */
8400 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
8401 if (*args[4])
8402 reqlen += strlen(args[4]);
8403 else
8404 reqlen += strlen("HTTP/1.0");
8405
8406 curproxy->check_req = (char *)malloc(reqlen);
8407 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
8408 "%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 +01008409 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008410 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008411 else if (!strcmp(args[1], "persist")) {
8412 /* persist on using the server specified by the cookie, even when it's down */
8413 curproxy->options |= PR_O_PERSIST;
8414 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008415 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008416 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008417 return -1;
8418 }
8419 return 0;
8420 }
8421 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
8422 /* enable reconnections to dispatch */
8423 curproxy->options |= PR_O_REDISP;
8424 }
willy tarreaua1598082005-12-17 13:08:06 +01008425#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01008426 else if (!strcmp(args[0], "transparent")) {
8427 /* enable transparent proxy connections */
8428 curproxy->options |= PR_O_TRANSP;
8429 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008430#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01008431 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
8432 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008433 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008434 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008435 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008436 curproxy->maxconn = atol(args[1]);
8437 }
8438 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
8439 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008440 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008441 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008442 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008443 curproxy->grace = atol(args[1]);
8444 }
8445 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01008446 if (curproxy == &defproxy) {
8447 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8448 return -1;
8449 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008450 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008451 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008452 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008453 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008454 curproxy->dispatch_addr = *str2sa(args[1]);
8455 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008456 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01008457 if (*(args[1])) {
8458 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008459 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01008460 }
willy tarreau1a3442d2006-03-24 21:03:20 +01008461 else if (!strcmp(args[1], "source")) {
8462 curproxy->options |= PR_O_BALANCE_SH;
8463 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008464 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01008465 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008466 return -1;
8467 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008468 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008469 else /* if no option is set, use round-robin by default */
8470 curproxy->options |= PR_O_BALANCE_RR;
8471 }
8472 else if (!strcmp(args[0], "server")) { /* server address */
8473 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008474 char *rport;
8475 char *raddr;
8476 short realport;
8477 int do_check;
8478
8479 if (curproxy == &defproxy) {
8480 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8481 return -1;
8482 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008483
willy tarreaua41a8b42005-12-17 14:02:24 +01008484 if (!*args[2]) {
8485 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008486 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008487 return -1;
8488 }
8489 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
8490 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8491 return -1;
8492 }
willy tarreau0174f312005-12-18 01:02:42 +01008493
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008494 /* the servers are linked backwards first */
8495 newsrv->next = curproxy->srv;
8496 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01008497 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008498
willy tarreau18a957c2006-04-12 19:26:23 +02008499 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01008500 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01008501 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01008502 newsrv->id = strdup(args[1]);
8503
8504 /* several ways to check the port component :
8505 * - IP => port=+0, relative
8506 * - IP: => port=+0, relative
8507 * - IP:N => port=N, absolute
8508 * - IP:+N => port=+N, relative
8509 * - IP:-N => port=-N, relative
8510 */
8511 raddr = strdup(args[2]);
8512 rport = strchr(raddr, ':');
8513 if (rport) {
8514 *rport++ = 0;
8515 realport = atol(rport);
8516 if (!isdigit((int)*rport))
8517 newsrv->state |= SRV_MAPPORTS;
8518 } else {
8519 realport = 0;
8520 newsrv->state |= SRV_MAPPORTS;
8521 }
8522
8523 newsrv->addr = *str2sa(raddr);
8524 newsrv->addr.sin_port = htons(realport);
8525 free(raddr);
8526
willy tarreau9fe663a2005-12-17 13:02:59 +01008527 newsrv->curfd = -1; /* no health-check in progress */
8528 newsrv->inter = DEF_CHKINTR;
8529 newsrv->rise = DEF_RISETIME;
8530 newsrv->fall = DEF_FALLTIME;
8531 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
8532 cur_arg = 3;
8533 while (*args[cur_arg]) {
8534 if (!strcmp(args[cur_arg], "cookie")) {
8535 newsrv->cookie = strdup(args[cur_arg + 1]);
8536 newsrv->cklen = strlen(args[cur_arg + 1]);
8537 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01008538 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008539 else if (!strcmp(args[cur_arg], "rise")) {
8540 newsrv->rise = atol(args[cur_arg + 1]);
8541 newsrv->health = newsrv->rise;
8542 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01008543 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008544 else if (!strcmp(args[cur_arg], "fall")) {
8545 newsrv->fall = atol(args[cur_arg + 1]);
8546 cur_arg += 2;
8547 }
8548 else if (!strcmp(args[cur_arg], "inter")) {
8549 newsrv->inter = atol(args[cur_arg + 1]);
8550 cur_arg += 2;
8551 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008552 else if (!strcmp(args[cur_arg], "port")) {
8553 newsrv->check_port = atol(args[cur_arg + 1]);
8554 cur_arg += 2;
8555 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008556 else if (!strcmp(args[cur_arg], "backup")) {
8557 newsrv->state |= SRV_BACKUP;
8558 cur_arg ++;
8559 }
willy tarreaue3f023f2006-04-08 21:52:24 +02008560 else if (!strcmp(args[cur_arg], "weight")) {
8561 int w;
8562 w = atol(args[cur_arg + 1]);
8563 if (w < 1 || w > 256) {
8564 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
8565 file, linenum, newsrv->id, w);
8566 return -1;
8567 }
8568 newsrv->uweight = w - 1;
8569 cur_arg += 2;
8570 }
willy tarreauf76e6ca2006-05-21 21:09:55 +02008571 else if (!strcmp(args[cur_arg], "minconn")) {
8572 newsrv->minconn = atol(args[cur_arg + 1]);
8573 cur_arg += 2;
8574 }
willy tarreau18a957c2006-04-12 19:26:23 +02008575 else if (!strcmp(args[cur_arg], "maxconn")) {
8576 newsrv->maxconn = atol(args[cur_arg + 1]);
8577 cur_arg += 2;
8578 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008579 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01008580 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01008581 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008582 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008583 }
willy tarreau0174f312005-12-18 01:02:42 +01008584 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
8585 if (!*args[cur_arg + 1]) {
8586 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
8587 file, linenum, "source");
8588 return -1;
8589 }
8590 newsrv->state |= SRV_BIND_SRC;
8591 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
8592 cur_arg += 2;
8593 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008594 else {
willy tarreauf76e6ca2006-05-21 21:09:55 +02008595 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port', 'source', 'minconn', 'maxconn' and 'weight'.\n",
willy tarreaua41a8b42005-12-17 14:02:24 +01008596 file, linenum, newsrv->id);
8597 return -1;
8598 }
8599 }
8600
8601 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008602 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
8603 newsrv->check_port = realport; /* by default */
8604 if (!newsrv->check_port) {
8605 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 +01008606 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01008607 return -1;
8608 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008609 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01008610 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008611
willy tarreau62084d42006-03-24 18:57:41 +01008612 if (newsrv->state & SRV_BACKUP)
8613 curproxy->srv_bck++;
8614 else
8615 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01008616 }
8617 else if (!strcmp(args[0], "log")) { /* syslog server address */
8618 struct sockaddr_in *sa;
8619 int facility;
8620
8621 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
8622 curproxy->logfac1 = global.logfac1;
8623 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01008624 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008625 curproxy->logfac2 = global.logfac2;
8626 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01008627 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01008628 }
8629 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01008630 int level;
8631
willy tarreau0f7af912005-12-17 12:21:26 +01008632 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
8633 if (!strcmp(log_facilities[facility], args[2]))
8634 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01008635
willy tarreau0f7af912005-12-17 12:21:26 +01008636 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008637 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01008638 exit(1);
8639 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008640
willy tarreau8337c6b2005-12-17 13:41:01 +01008641 level = 7; /* max syslog level = debug */
8642 if (*(args[3])) {
8643 while (level >= 0 && strcmp(log_levels[level], args[3]))
8644 level--;
8645 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008646 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008647 exit(1);
8648 }
8649 }
8650
willy tarreau0f7af912005-12-17 12:21:26 +01008651 sa = str2sa(args[1]);
8652 if (!sa->sin_port)
8653 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01008654
willy tarreau0f7af912005-12-17 12:21:26 +01008655 if (curproxy->logfac1 == -1) {
8656 curproxy->logsrv1 = *sa;
8657 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01008658 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01008659 }
8660 else if (curproxy->logfac2 == -1) {
8661 curproxy->logsrv2 = *sa;
8662 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01008663 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01008664 }
8665 else {
8666 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01008667 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008668 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008669 }
8670 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008671 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01008672 file, linenum);
8673 return -1;
8674 }
8675 }
willy tarreaua1598082005-12-17 13:08:06 +01008676 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01008677 if (!*args[1]) {
8678 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008679 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01008680 return -1;
8681 }
8682
8683 curproxy->source_addr = *str2sa(args[1]);
8684 curproxy->options |= PR_O_BIND_SRC;
8685 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008686 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
8687 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008688 if (curproxy == &defproxy) {
8689 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8690 return -1;
8691 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008692
8693 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008694 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8695 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008696 return -1;
8697 }
8698
8699 preg = calloc(1, sizeof(regex_t));
8700 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008701 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008702 return -1;
8703 }
8704
willy tarreauc1f47532005-12-18 01:08:26 +01008705 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8706 if (err) {
8707 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8708 file, linenum, *err);
8709 return -1;
8710 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008711 }
8712 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
8713 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008714 if (curproxy == &defproxy) {
8715 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8716 return -1;
8717 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008718
8719 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008720 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008721 return -1;
8722 }
8723
8724 preg = calloc(1, sizeof(regex_t));
8725 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008726 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008727 return -1;
8728 }
8729
8730 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8731 }
8732 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
8733 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008734 if (curproxy == &defproxy) {
8735 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8736 return -1;
8737 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008738
8739 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008740 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008741 return -1;
8742 }
8743
8744 preg = calloc(1, sizeof(regex_t));
8745 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008746 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008747 return -1;
8748 }
8749
8750 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8751 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008752 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
8753 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008754 if (curproxy == &defproxy) {
8755 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8756 return -1;
8757 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008758
8759 if (*(args[1]) == 0) {
8760 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8761 return -1;
8762 }
8763
8764 preg = calloc(1, sizeof(regex_t));
8765 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8766 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8767 return -1;
8768 }
8769
8770 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8771 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008772 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
8773 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008774 if (curproxy == &defproxy) {
8775 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8776 return -1;
8777 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008778
8779 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008780 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008781 return -1;
8782 }
8783
8784 preg = calloc(1, sizeof(regex_t));
8785 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008786 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008787 return -1;
8788 }
8789
8790 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8791 }
8792 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
8793 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008794 if (curproxy == &defproxy) {
8795 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8796 return -1;
8797 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008798
8799 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008800 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8801 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008802 return -1;
8803 }
8804
8805 preg = calloc(1, sizeof(regex_t));
8806 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008807 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008808 return -1;
8809 }
8810
willy tarreauc1f47532005-12-18 01:08:26 +01008811 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8812 if (err) {
8813 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8814 file, linenum, *err);
8815 return -1;
8816 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008817 }
8818 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
8819 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008820 if (curproxy == &defproxy) {
8821 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8822 return -1;
8823 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008824
8825 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008826 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008827 return -1;
8828 }
8829
8830 preg = calloc(1, sizeof(regex_t));
8831 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008832 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008833 return -1;
8834 }
8835
8836 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8837 }
8838 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
8839 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008840 if (curproxy == &defproxy) {
8841 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8842 return -1;
8843 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008844
8845 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008846 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008847 return -1;
8848 }
8849
8850 preg = calloc(1, sizeof(regex_t));
8851 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008852 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008853 return -1;
8854 }
8855
8856 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8857 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008858 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
8859 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008860 if (curproxy == &defproxy) {
8861 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8862 return -1;
8863 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008864
8865 if (*(args[1]) == 0) {
8866 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8867 return -1;
8868 }
8869
8870 preg = calloc(1, sizeof(regex_t));
8871 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8872 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8873 return -1;
8874 }
8875
8876 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8877 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008878 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
8879 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008880 if (curproxy == &defproxy) {
8881 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8882 return -1;
8883 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008884
8885 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008886 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008887 return -1;
8888 }
8889
8890 preg = calloc(1, sizeof(regex_t));
8891 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008892 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008893 return -1;
8894 }
8895
8896 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8897 }
8898 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008899 if (curproxy == &defproxy) {
8900 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8901 return -1;
8902 }
8903
willy tarreau9fe663a2005-12-17 13:02:59 +01008904 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008905 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008906 return 0;
8907 }
8908
8909 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008910 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008911 return -1;
8912 }
8913
willy tarreau4302f492005-12-18 01:00:37 +01008914 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
8915 }
8916 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
8917 regex_t *preg;
8918
8919 if (*(args[1]) == 0 || *(args[2]) == 0) {
8920 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8921 file, linenum, args[0]);
8922 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008923 }
willy tarreau4302f492005-12-18 01:00:37 +01008924
8925 preg = calloc(1, sizeof(regex_t));
8926 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8927 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8928 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008929 }
willy tarreau4302f492005-12-18 01:00:37 +01008930
willy tarreauc1f47532005-12-18 01:08:26 +01008931 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8932 if (err) {
8933 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8934 file, linenum, *err);
8935 return -1;
8936 }
willy tarreau4302f492005-12-18 01:00:37 +01008937 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008938 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
8939 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008940 if (curproxy == &defproxy) {
8941 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8942 return -1;
8943 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008944
8945 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008946 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008947 return -1;
8948 }
willy tarreaue39cd132005-12-17 13:00:18 +01008949
willy tarreau9fe663a2005-12-17 13:02:59 +01008950 preg = calloc(1, sizeof(regex_t));
8951 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008952 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008953 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008954 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008955
willy tarreauc1f47532005-12-18 01:08:26 +01008956 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8957 if (err) {
8958 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8959 file, linenum, *err);
8960 return -1;
8961 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008962 }
willy tarreau982249e2005-12-18 00:57:06 +01008963 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
8964 regex_t *preg;
8965 if (curproxy == &defproxy) {
8966 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8967 return -1;
8968 }
8969
8970 if (*(args[1]) == 0) {
8971 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8972 return -1;
8973 }
8974
8975 preg = calloc(1, sizeof(regex_t));
8976 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8977 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8978 return -1;
8979 }
8980
willy tarreauc1f47532005-12-18 01:08:26 +01008981 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8982 if (err) {
8983 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8984 file, linenum, *err);
8985 return -1;
8986 }
willy tarreau982249e2005-12-18 00:57:06 +01008987 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008988 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01008989 regex_t *preg;
8990 if (curproxy == &defproxy) {
8991 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8992 return -1;
8993 }
willy tarreaue39cd132005-12-17 13:00:18 +01008994
willy tarreaua41a8b42005-12-17 14:02:24 +01008995 if (*(args[1]) == 0 || *(args[2]) == 0) {
8996 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8997 file, linenum, args[0]);
8998 return -1;
8999 }
willy tarreaue39cd132005-12-17 13:00:18 +01009000
willy tarreaua41a8b42005-12-17 14:02:24 +01009001 preg = calloc(1, sizeof(regex_t));
9002 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
9003 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
9004 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01009005 }
willy tarreaua41a8b42005-12-17 14:02:24 +01009006
willy tarreauc1f47532005-12-18 01:08:26 +01009007 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
9008 if (err) {
9009 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
9010 file, linenum, *err);
9011 return -1;
9012 }
willy tarreaua41a8b42005-12-17 14:02:24 +01009013 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009014 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
9015 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01009016 if (curproxy == &defproxy) {
9017 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9018 return -1;
9019 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009020
9021 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009022 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009023 return -1;
9024 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009025
willy tarreau9fe663a2005-12-17 13:02:59 +01009026 preg = calloc(1, sizeof(regex_t));
9027 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009028 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009029 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01009030 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009031
willy tarreauc1f47532005-12-18 01:08:26 +01009032 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
9033 if (err) {
9034 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
9035 file, linenum, *err);
9036 return -1;
9037 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009038 }
willy tarreau982249e2005-12-18 00:57:06 +01009039 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
9040 regex_t *preg;
9041 if (curproxy == &defproxy) {
9042 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9043 return -1;
9044 }
9045
9046 if (*(args[1]) == 0) {
9047 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
9048 return -1;
9049 }
9050
9051 preg = calloc(1, sizeof(regex_t));
9052 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
9053 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
9054 return -1;
9055 }
9056
willy tarreauc1f47532005-12-18 01:08:26 +01009057 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
9058 if (err) {
9059 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
9060 file, linenum, *err);
9061 return -1;
9062 }
willy tarreau982249e2005-12-18 00:57:06 +01009063 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009064 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01009065 if (curproxy == &defproxy) {
9066 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9067 return -1;
9068 }
9069
willy tarreau9fe663a2005-12-17 13:02:59 +01009070 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009071 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009072 return 0;
9073 }
9074
9075 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009076 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009077 return -1;
9078 }
9079
9080 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
9081 }
willy tarreauc1f47532005-12-18 01:08:26 +01009082 else if (!strcmp(args[0], "errorloc") ||
9083 !strcmp(args[0], "errorloc302") ||
9084 !strcmp(args[0], "errorloc303")) { /* error location */
9085 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009086 char *err;
9087
willy tarreaueedaa9f2005-12-17 14:08:03 +01009088 // if (curproxy == &defproxy) {
9089 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9090 // return -1;
9091 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01009092
willy tarreau8337c6b2005-12-17 13:41:01 +01009093 if (*(args[2]) == 0) {
9094 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
9095 return -1;
9096 }
9097
9098 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01009099 if (!strcmp(args[0], "errorloc303")) {
9100 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
9101 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
9102 } else {
9103 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
9104 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
9105 }
willy tarreau8337c6b2005-12-17 13:41:01 +01009106
9107 if (errnum == 400) {
9108 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009109 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009110 free(curproxy->errmsg.msg400);
9111 }
9112 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009113 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009114 }
9115 else if (errnum == 403) {
9116 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009117 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009118 free(curproxy->errmsg.msg403);
9119 }
9120 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009121 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009122 }
9123 else if (errnum == 408) {
9124 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009125 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009126 free(curproxy->errmsg.msg408);
9127 }
9128 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009129 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009130 }
9131 else if (errnum == 500) {
9132 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009133 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009134 free(curproxy->errmsg.msg500);
9135 }
9136 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009137 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009138 }
9139 else if (errnum == 502) {
9140 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009141 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009142 free(curproxy->errmsg.msg502);
9143 }
9144 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009145 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009146 }
9147 else if (errnum == 503) {
9148 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009149 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009150 free(curproxy->errmsg.msg503);
9151 }
9152 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009153 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009154 }
9155 else if (errnum == 504) {
9156 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009157 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009158 free(curproxy->errmsg.msg504);
9159 }
9160 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009161 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009162 }
9163 else {
9164 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
9165 free(err);
9166 }
9167 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009168 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01009169 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01009170 return -1;
9171 }
9172 return 0;
9173}
willy tarreaue39cd132005-12-17 13:00:18 +01009174
willy tarreau5cbea6f2005-12-17 12:48:26 +01009175
willy tarreau9fe663a2005-12-17 13:02:59 +01009176/*
9177 * This function reads and parses the configuration file given in the argument.
9178 * returns 0 if OK, -1 if error.
9179 */
9180int readcfgfile(char *file) {
9181 char thisline[256];
9182 char *line;
9183 FILE *f;
9184 int linenum = 0;
9185 char *end;
9186 char *args[MAX_LINE_ARGS];
9187 int arg;
9188 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01009189 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01009190 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01009191
willy tarreau9fe663a2005-12-17 13:02:59 +01009192 struct proxy *curproxy = NULL;
9193 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01009194
willy tarreau9fe663a2005-12-17 13:02:59 +01009195 if ((f=fopen(file,"r")) == NULL)
9196 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01009197
willy tarreaueedaa9f2005-12-17 14:08:03 +01009198 init_default_instance();
9199
willy tarreau9fe663a2005-12-17 13:02:59 +01009200 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
9201 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009202
willy tarreau9fe663a2005-12-17 13:02:59 +01009203 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01009204
willy tarreau9fe663a2005-12-17 13:02:59 +01009205 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01009206 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01009207 line++;
9208
9209 arg = 0;
9210 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01009211
willy tarreau9fe663a2005-12-17 13:02:59 +01009212 while (*line && arg < MAX_LINE_ARGS) {
9213 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
9214 * C equivalent value. Other combinations left unchanged (eg: \1).
9215 */
9216 if (*line == '\\') {
9217 int skip = 0;
9218 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
9219 *line = line[1];
9220 skip = 1;
9221 }
9222 else if (line[1] == 'r') {
9223 *line = '\r';
9224 skip = 1;
9225 }
9226 else if (line[1] == 'n') {
9227 *line = '\n';
9228 skip = 1;
9229 }
9230 else if (line[1] == 't') {
9231 *line = '\t';
9232 skip = 1;
9233 }
willy tarreauc1f47532005-12-18 01:08:26 +01009234 else if (line[1] == 'x') {
9235 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
9236 unsigned char hex1, hex2;
9237 hex1 = toupper(line[2]) - '0';
9238 hex2 = toupper(line[3]) - '0';
9239 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
9240 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
9241 *line = (hex1<<4) + hex2;
9242 skip = 3;
9243 }
9244 else {
9245 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
9246 return -1;
9247 }
9248 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009249 if (skip) {
9250 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
9251 end -= skip;
9252 }
9253 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01009254 }
willy tarreaua1598082005-12-17 13:08:06 +01009255 else if (*line == '#' || *line == '\n' || *line == '\r') {
9256 /* end of string, end of loop */
9257 *line = 0;
9258 break;
9259 }
willy tarreauc29948c2005-12-17 13:10:27 +01009260 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009261 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01009262 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01009263 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01009264 line++;
9265 args[++arg] = line;
9266 }
9267 else {
9268 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01009269 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009270 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009271
willy tarreau9fe663a2005-12-17 13:02:59 +01009272 /* empty line */
9273 if (!**args)
9274 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01009275
willy tarreau9fe663a2005-12-17 13:02:59 +01009276 /* zero out remaining args */
9277 while (++arg < MAX_LINE_ARGS) {
9278 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009279 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009280
willy tarreaua41a8b42005-12-17 14:02:24 +01009281 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01009282 confsect = CFG_LISTEN;
9283 else if (!strcmp(args[0], "global")) /* global config */
9284 confsect = CFG_GLOBAL;
9285 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01009286
willy tarreau9fe663a2005-12-17 13:02:59 +01009287 switch (confsect) {
9288 case CFG_LISTEN:
9289 if (cfg_parse_listen(file, linenum, args) < 0)
9290 return -1;
9291 break;
9292 case CFG_GLOBAL:
9293 if (cfg_parse_global(file, linenum, args) < 0)
9294 return -1;
9295 break;
9296 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01009297 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009298 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01009299 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009300
9301
willy tarreau0f7af912005-12-17 12:21:26 +01009302 }
9303 fclose(f);
9304
9305 /*
9306 * Now, check for the integrity of all that we have collected.
9307 */
9308
Willy TARREAU3759f982006-03-01 22:44:17 +01009309 /* will be needed further to delay some tasks */
9310 tv_now(&now);
9311
willy tarreau0f7af912005-12-17 12:21:26 +01009312 if ((curproxy = proxy) == NULL) {
9313 Alert("parsing %s : no <listen> line. Nothing to do !\n",
9314 file);
9315 return -1;
9316 }
9317
9318 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01009319 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01009320 curproxy = curproxy->next;
9321 continue;
9322 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009323
9324 if (curproxy->listen == NULL) {
9325 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);
9326 cfgerr++;
9327 }
9328 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01009329 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01009330 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01009331 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
9332 file, curproxy->id);
9333 cfgerr++;
9334 }
9335 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
9336 if (curproxy->options & PR_O_TRANSP) {
9337 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
9338 file, curproxy->id);
9339 cfgerr++;
9340 }
willy tarreau38d79062006-05-21 14:47:13 +02009341#ifdef WE_DONT_SUPPORT_SERVERLESS_LISTENERS
willy tarreau5cbea6f2005-12-17 12:48:26 +01009342 else if (curproxy->srv == NULL) {
9343 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
9344 file, curproxy->id);
9345 cfgerr++;
9346 }
willy tarreau38d79062006-05-21 14:47:13 +02009347#endif
willy tarreaua1598082005-12-17 13:08:06 +01009348 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01009349 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
9350 file, curproxy->id);
9351 }
9352 }
9353 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01009354 if (curproxy->cookie_name != NULL) {
9355 Warning("parsing %s : cookie will be ignored for listener %s.\n",
9356 file, curproxy->id);
9357 }
9358 if ((newsrv = curproxy->srv) != NULL) {
9359 Warning("parsing %s : servers will be ignored for listener %s.\n",
9360 file, curproxy->id);
9361 }
willy tarreaue39cd132005-12-17 13:00:18 +01009362 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01009363 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
9364 file, curproxy->id);
9365 }
willy tarreaue39cd132005-12-17 13:00:18 +01009366 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01009367 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
9368 file, curproxy->id);
9369 }
9370 }
9371 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
9372 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
9373 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
9374 file, curproxy->id);
9375 cfgerr++;
9376 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009377 }
willy tarreaue3f023f2006-04-08 21:52:24 +02009378
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009379 /* first, we will invert the servers list order */
9380 newsrv = NULL;
9381 while (curproxy->srv) {
9382 struct server *next;
9383
9384 next = curproxy->srv->next;
9385 curproxy->srv->next = newsrv;
9386 newsrv = curproxy->srv;
9387 if (!next)
9388 break;
9389 curproxy->srv = next;
9390 }
9391
9392 /* now, newsrv == curproxy->srv */
9393 if (newsrv) {
9394 struct server *srv;
9395 int pgcd;
9396 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02009397
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009398 /* We will factor the weights to reduce the table,
9399 * using Euclide's largest common divisor algorithm
9400 */
9401 pgcd = newsrv->uweight + 1;
9402 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
9403 int t, w;
9404
9405 w = srv->uweight + 1;
9406 while (w) {
9407 t = pgcd % w;
9408 pgcd = w;
9409 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02009410 }
willy tarreau0f7af912005-12-17 12:21:26 +01009411 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009412
9413 act = bck = 0;
9414 for (srv = newsrv; srv; srv = srv->next) {
9415 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
9416 if (srv->state & SRV_BACKUP)
9417 bck += srv->eweight + 1;
9418 else
9419 act += srv->eweight + 1;
9420 }
9421
9422 /* this is the largest map we will ever need for this servers list */
9423 if (act < bck)
9424 act = bck;
9425
9426 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
9427 /* recounts servers and their weights */
9428 recount_servers(curproxy);
9429 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01009430 }
willy tarreau25c4ea52005-12-18 00:49:49 +01009431
9432 if (curproxy->options & PR_O_LOGASAP)
9433 curproxy->to_log &= ~LW_BYTES;
9434
willy tarreau8337c6b2005-12-17 13:41:01 +01009435 if (curproxy->errmsg.msg400 == NULL) {
9436 curproxy->errmsg.msg400 = (char *)HTTP_400;
9437 curproxy->errmsg.len400 = strlen(HTTP_400);
9438 }
9439 if (curproxy->errmsg.msg403 == NULL) {
9440 curproxy->errmsg.msg403 = (char *)HTTP_403;
9441 curproxy->errmsg.len403 = strlen(HTTP_403);
9442 }
9443 if (curproxy->errmsg.msg408 == NULL) {
9444 curproxy->errmsg.msg408 = (char *)HTTP_408;
9445 curproxy->errmsg.len408 = strlen(HTTP_408);
9446 }
9447 if (curproxy->errmsg.msg500 == NULL) {
9448 curproxy->errmsg.msg500 = (char *)HTTP_500;
9449 curproxy->errmsg.len500 = strlen(HTTP_500);
9450 }
9451 if (curproxy->errmsg.msg502 == NULL) {
9452 curproxy->errmsg.msg502 = (char *)HTTP_502;
9453 curproxy->errmsg.len502 = strlen(HTTP_502);
9454 }
9455 if (curproxy->errmsg.msg503 == NULL) {
9456 curproxy->errmsg.msg503 = (char *)HTTP_503;
9457 curproxy->errmsg.len503 = strlen(HTTP_503);
9458 }
9459 if (curproxy->errmsg.msg504 == NULL) {
9460 curproxy->errmsg.msg504 = (char *)HTTP_504;
9461 curproxy->errmsg.len504 = strlen(HTTP_504);
9462 }
Willy TARREAU3759f982006-03-01 22:44:17 +01009463
willy tarreau59a6cc22006-05-12 01:29:08 +02009464 /*
9465 * If this server supports a maxconn parameter, it needs a dedicated
9466 * tasks to fill the emptied slots when a connection leaves.
9467 */
9468 newsrv = curproxy->srv;
9469 while (newsrv != NULL) {
willy tarreau2b598cc2006-05-21 22:07:31 +02009470 if (newsrv->minconn >= newsrv->maxconn) {
9471 /* Only 'minconn' was specified, or it was higher than or equal
9472 * to 'maxconn'. Let's turn this into maxconn and clean it, as
9473 * this will avoid further useless expensive computations.
9474 */
willy tarreauf76e6ca2006-05-21 21:09:55 +02009475 newsrv->maxconn = newsrv->minconn;
9476 newsrv->minconn = 0;
9477 }
9478
willy tarreau59a6cc22006-05-12 01:29:08 +02009479 if (newsrv->maxconn > 0) {
9480 struct task *t;
9481
9482 if ((t = pool_alloc(task)) == NULL) {
9483 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
9484 return -1;
9485 }
9486
9487 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
9488 t->wq = LIST_HEAD(wait_queue[1]); /* already assigned to the eternity queue */
9489 t->state = TASK_IDLE;
9490 t->process = process_srv_queue;
9491 t->context = newsrv;
9492 newsrv->queue_mgt = t;
9493
9494 /* never run it unless specifically woken up */
9495 tv_eternity(&t->expire);
9496 task_queue(t);
9497 }
9498 newsrv = newsrv->next;
9499 }
9500
Willy TARREAU3759f982006-03-01 22:44:17 +01009501 /* now we'll start this proxy's health checks if any */
9502 /* 1- count the checkers to run simultaneously */
9503 nbchk = 0;
9504 mininter = 0;
9505 newsrv = curproxy->srv;
9506 while (newsrv != NULL) {
9507 if (newsrv->state & SRV_CHECKED) {
9508 if (!mininter || mininter > newsrv->inter)
9509 mininter = newsrv->inter;
9510 nbchk++;
9511 }
9512 newsrv = newsrv->next;
9513 }
9514
9515 /* 2- start them as far as possible from each others while respecting
9516 * their own intervals. For this, we will start them after their own
9517 * interval added to the min interval divided by the number of servers,
9518 * weighted by the server's position in the list.
9519 */
9520 if (nbchk > 0) {
9521 struct task *t;
9522 int srvpos;
9523
9524 newsrv = curproxy->srv;
9525 srvpos = 0;
9526 while (newsrv != NULL) {
9527 /* should this server be checked ? */
9528 if (newsrv->state & SRV_CHECKED) {
9529 if ((t = pool_alloc(task)) == NULL) {
9530 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
9531 return -1;
9532 }
9533
9534 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02009535 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
Willy TARREAU3759f982006-03-01 22:44:17 +01009536 t->state = TASK_IDLE;
9537 t->process = process_chk;
9538 t->context = newsrv;
9539
9540 /* check this every ms */
9541 tv_delayfrom(&t->expire, &now,
9542 newsrv->inter + mininter * srvpos / nbchk);
9543 task_queue(t);
9544 //task_wakeup(&rq, t);
9545 srvpos++;
9546 }
9547 newsrv = newsrv->next;
9548 }
9549 }
9550
willy tarreau0f7af912005-12-17 12:21:26 +01009551 curproxy = curproxy->next;
9552 }
9553 if (cfgerr > 0) {
9554 Alert("Errors found in configuration file, aborting.\n");
9555 return -1;
9556 }
9557 else
9558 return 0;
9559}
9560
9561
9562/*
9563 * This function initializes all the necessary variables. It only returns
9564 * if everything is OK. If something fails, it exits.
9565 */
9566void init(int argc, char **argv) {
9567 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01009568 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01009569 char *old_argv = *argv;
9570 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009571 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009572
9573 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01009574 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01009575 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01009576 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01009577 exit(1);
9578 }
9579
willy tarreau746e26b2006-03-25 11:14:35 +01009580#ifdef HAPROXY_MEMMAX
9581 global.rlimit_memmax = HAPROXY_MEMMAX;
9582#endif
9583
Willy TARREAUa9e75f62006-03-01 22:27:48 +01009584 /* initialize the libc's localtime structures once for all so that we
9585 * won't be missing memory if we want to send alerts under OOM conditions.
9586 */
9587 tv_now(&now);
9588 localtime(&now.tv_sec);
willy tarreaue0331262006-05-15 03:02:46 +02009589 start_date = now;
Willy TARREAUa9e75f62006-03-01 22:27:48 +01009590
willy tarreau4302f492005-12-18 01:00:37 +01009591 /* initialize the log header encoding map : '{|}"#' should be encoded with
9592 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
9593 * URL encoding only requires '"', '#' to be encoded as well as non-
9594 * printable characters above.
9595 */
9596 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
9597 memset(url_encode_map, 0, sizeof(url_encode_map));
9598 for (i = 0; i < 32; i++) {
9599 FD_SET(i, hdr_encode_map);
9600 FD_SET(i, url_encode_map);
9601 }
9602 for (i = 127; i < 256; i++) {
9603 FD_SET(i, hdr_encode_map);
9604 FD_SET(i, url_encode_map);
9605 }
9606
9607 tmp = "\"#{|}";
9608 while (*tmp) {
9609 FD_SET(*tmp, hdr_encode_map);
9610 tmp++;
9611 }
9612
9613 tmp = "\"#";
9614 while (*tmp) {
9615 FD_SET(*tmp, url_encode_map);
9616 tmp++;
9617 }
9618
willy tarreau64a3cc32005-12-18 01:13:11 +01009619 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
9620#if defined(ENABLE_POLL)
9621 cfg_polling_mechanism |= POLL_USE_POLL;
9622#endif
9623#if defined(ENABLE_EPOLL)
9624 cfg_polling_mechanism |= POLL_USE_EPOLL;
9625#endif
9626
willy tarreau0f7af912005-12-17 12:21:26 +01009627 pid = getpid();
9628 progname = *argv;
9629 while ((tmp = strchr(progname, '/')) != NULL)
9630 progname = tmp + 1;
9631
9632 argc--; argv++;
9633 while (argc > 0) {
9634 char *flag;
9635
9636 if (**argv == '-') {
9637 flag = *argv+1;
9638
9639 /* 1 arg */
9640 if (*flag == 'v') {
9641 display_version();
9642 exit(0);
9643 }
willy tarreau1c2ad212005-12-18 01:11:29 +01009644#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009645 else if (*flag == 'd' && flag[1] == 'e')
9646 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009647#endif
9648#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009649 else if (*flag == 'd' && flag[1] == 'p')
9650 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009651#endif
willy tarreau982249e2005-12-18 00:57:06 +01009652 else if (*flag == 'V')
9653 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009654 else if (*flag == 'd' && flag[1] == 'b')
9655 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01009656 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01009657 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01009658 else if (*flag == 'c')
9659 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01009660 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01009661 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009662 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01009663 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01009664 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
9665 /* list of pids to finish ('f') or terminate ('t') */
9666
9667 if (flag[1] == 'f')
9668 oldpids_sig = SIGUSR1; /* finish then exit */
9669 else
9670 oldpids_sig = SIGTERM; /* terminate immediately */
9671 argv++; argc--;
9672
9673 if (argc > 0) {
9674 oldpids = calloc(argc, sizeof(int));
9675 while (argc > 0) {
9676 oldpids[nb_oldpids] = atol(*argv);
9677 if (oldpids[nb_oldpids] <= 0)
9678 usage(old_argv);
9679 argc--; argv++;
9680 nb_oldpids++;
9681 }
9682 }
9683 }
willy tarreau2c513732006-04-15 19:25:16 +02009684#if STATTIME > 0
9685 else if (*flag == 's')
9686 arg_mode |= MODE_STATS;
9687 else if (*flag == 'l')
9688 arg_mode |= MODE_LOG;
9689#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009690 else { /* >=2 args */
9691 argv++; argc--;
9692 if (argc == 0)
9693 usage(old_argv);
9694
9695 switch (*flag) {
9696 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01009697 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01009698 case 'N' : cfg_maxpconn = atol(*argv); break;
9699 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009700 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01009701 default: usage(old_argv);
9702 }
9703 }
9704 }
9705 else
9706 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01009707 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01009708 }
9709
willy tarreaud0fb4652005-12-18 01:32:04 +01009710 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009711 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
9712 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01009713
willy tarreau0f7af912005-12-17 12:21:26 +01009714 if (!cfg_cfgfile)
9715 usage(old_argv);
9716
9717 gethostname(hostname, MAX_HOSTNAME_LEN);
9718
willy tarreau12350152005-12-18 01:03:27 +01009719 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01009720 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01009721 if (readcfgfile(cfg_cfgfile) < 0) {
9722 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
9723 exit(1);
9724 }
willy tarreau12350152005-12-18 01:03:27 +01009725 if (have_appsession)
9726 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01009727
willy tarreau982249e2005-12-18 00:57:06 +01009728 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01009729 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
9730 exit(0);
9731 }
9732
willy tarreau9fe663a2005-12-17 13:02:59 +01009733 if (cfg_maxconn > 0)
9734 global.maxconn = cfg_maxconn;
9735
willy tarreaufe2c5c12005-12-17 14:14:34 +01009736 if (cfg_pidfile) {
9737 if (global.pidfile)
9738 free(global.pidfile);
9739 global.pidfile = strdup(cfg_pidfile);
9740 }
9741
willy tarreau9fe663a2005-12-17 13:02:59 +01009742 if (global.maxconn == 0)
9743 global.maxconn = DEFAULT_MAXCONN;
9744
Willy TARREAU203b0b62006-03-12 18:00:28 +01009745 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01009746
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009747 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009748 /* command line debug mode inhibits configuration mode */
9749 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
9750 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009751 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
9752 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01009753
9754 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
9755 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
9756 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
9757 }
9758
9759 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009760 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
9761 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01009762 global.nbproc = 1;
9763 }
9764
9765 if (global.nbproc < 1)
9766 global.nbproc = 1;
9767
willy tarreau0f7af912005-12-17 12:21:26 +01009768 StaticReadEvent = (fd_set *)calloc(1,
9769 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01009770 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01009771 StaticWriteEvent = (fd_set *)calloc(1,
9772 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01009773 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01009774
9775 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01009776 sizeof(struct fdtab) * (global.maxsock));
9777 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01009778 fdtab[i].state = FD_STCLOSE;
9779 }
9780}
9781
9782/*
willy tarreau41310e72006-03-25 18:17:56 +01009783 * this function starts all the proxies. Its return value is composed from
9784 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
9785 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01009786 */
willy tarreau41310e72006-03-25 18:17:56 +01009787int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01009788 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01009789 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01009790 int err = ERR_NONE;
9791 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01009792
9793 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01009794 if (curproxy->state != PR_STNEW)
9795 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01009796
willy tarreau41310e72006-03-25 18:17:56 +01009797 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01009798 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01009799 if (listener->fd != -1)
9800 continue; /* already initialized */
9801
9802 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
9803 if (verbose)
9804 Alert("cannot create listening socket for proxy %s. Aborting.\n",
9805 curproxy->id);
9806 err |= ERR_RETRYABLE;
9807 pxerr |= 1;
9808 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009809 }
willy tarreau0f7af912005-12-17 12:21:26 +01009810
willy tarreaua41a8b42005-12-17 14:02:24 +01009811 if (fd >= global.maxsock) {
9812 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
9813 curproxy->id);
9814 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009815 err |= ERR_FATAL;
9816 pxerr |= 1;
9817 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009818 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009819
willy tarreaua41a8b42005-12-17 14:02:24 +01009820 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
9821 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
9822 (char *) &one, sizeof(one)) == -1)) {
9823 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
9824 curproxy->id);
9825 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009826 err |= ERR_FATAL;
9827 pxerr |= 1;
9828 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009829 }
willy tarreau0f7af912005-12-17 12:21:26 +01009830
willy tarreaua41a8b42005-12-17 14:02:24 +01009831 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
9832 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
9833 curproxy->id);
9834 }
willy tarreau0f7af912005-12-17 12:21:26 +01009835
willy tarreaufac1a862006-05-21 10:20:28 +02009836#ifdef SO_REUSEPORT
9837 /* OpenBSD supports this. As it's present in old libc versions of Linux,
9838 * it might return an error that we will silently ignore.
9839 */
9840 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one));
9841#endif
willy tarreaua41a8b42005-12-17 14:02:24 +01009842 if (bind(fd,
9843 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01009844 listener->addr.ss_family == AF_INET6 ?
9845 sizeof(struct sockaddr_in6) :
9846 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009847 if (verbose)
9848 Alert("cannot bind socket for proxy %s. Aborting.\n",
9849 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009850 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009851 err |= ERR_RETRYABLE;
9852 pxerr |= 1;
9853 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009854 }
willy tarreau0f7af912005-12-17 12:21:26 +01009855
willy tarreaua41a8b42005-12-17 14:02:24 +01009856 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009857 if (verbose)
9858 Alert("cannot listen to socket for proxy %s. Aborting.\n",
9859 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009860 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009861 err |= ERR_RETRYABLE;
9862 pxerr |= 1;
9863 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009864 }
willy tarreau0f7af912005-12-17 12:21:26 +01009865
willy tarreau41310e72006-03-25 18:17:56 +01009866 /* the socket is ready */
9867 listener->fd = fd;
9868
willy tarreaua41a8b42005-12-17 14:02:24 +01009869 /* the function for the accept() event */
9870 fdtab[fd].read = &event_accept;
9871 fdtab[fd].write = NULL; /* never called */
9872 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01009873 fdtab[fd].state = FD_STLISTEN;
9874 FD_SET(fd, StaticReadEvent);
9875 fd_insert(fd);
9876 listeners++;
9877 }
willy tarreau41310e72006-03-25 18:17:56 +01009878
9879 if (!pxerr) {
9880 curproxy->state = PR_STRUN;
9881 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
9882 }
willy tarreau0f7af912005-12-17 12:21:26 +01009883 }
willy tarreau41310e72006-03-25 18:17:56 +01009884
9885 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01009886}
9887
willy tarreaub952e1d2005-12-18 01:31:20 +01009888int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01009889
9890 appsess *temp1,*temp2;
9891 temp1 = (appsess *)key1;
9892 temp2 = (appsess *)key2;
9893
9894 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
9895 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
9896
9897 return (strcmp(temp1->sessid,temp2->sessid) == 0);
9898}/* end match_str */
9899
willy tarreaub952e1d2005-12-18 01:31:20 +01009900void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01009901 appsess *temp1;
9902
9903 //printf("destroy called\n");
9904 temp1 = (appsess *)data;
9905
9906 if (temp1->sessid)
9907 pool_free_to(apools.sessid, temp1->sessid);
9908
9909 if (temp1->serverid)
9910 pool_free_to(apools.serverid, temp1->serverid);
9911
9912 pool_free(appsess, temp1);
9913} /* end destroy */
9914
9915void appsession_cleanup( void )
9916{
9917 struct proxy *p = proxy;
9918
9919 while(p) {
9920 chtbl_destroy(&(p->htbl_proxy));
9921 p = p->next;
9922 }
9923}/* end appsession_cleanup() */
9924
9925void pool_destroy(void **pool)
9926{
9927 void *temp, *next;
9928 next = pool;
9929 while (next) {
9930 temp = next;
9931 next = *(void **)temp;
9932 free(temp);
9933 }
9934}/* end pool_destroy() */
9935
willy tarreaub952e1d2005-12-18 01:31:20 +01009936void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01009937 struct proxy *p = proxy;
9938 struct cap_hdr *h,*h_next;
9939 struct server *s,*s_next;
9940 struct listener *l,*l_next;
9941
9942 while (p) {
9943 if (p->id)
9944 free(p->id);
9945
9946 if (p->check_req)
9947 free(p->check_req);
9948
9949 if (p->cookie_name)
9950 free(p->cookie_name);
9951
9952 if (p->capture_name)
9953 free(p->capture_name);
9954
9955 /* only strup if the user have set in config.
9956 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01009957 if (p->errmsg.msg400) free(p->errmsg.msg400);
9958 if (p->errmsg.msg403) free(p->errmsg.msg403);
9959 if (p->errmsg.msg408) free(p->errmsg.msg408);
9960 if (p->errmsg.msg500) free(p->errmsg.msg500);
9961 if (p->errmsg.msg502) free(p->errmsg.msg502);
9962 if (p->errmsg.msg503) free(p->errmsg.msg503);
9963 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01009964 */
9965 if (p->appsession_name)
9966 free(p->appsession_name);
9967
9968 h = p->req_cap;
9969 while (h) {
9970 h_next = h->next;
9971 if (h->name)
9972 free(h->name);
9973 pool_destroy(h->pool);
9974 free(h);
9975 h = h_next;
9976 }/* end while(h) */
9977
9978 h = p->rsp_cap;
9979 while (h) {
9980 h_next = h->next;
9981 if (h->name)
9982 free(h->name);
9983
9984 pool_destroy(h->pool);
9985 free(h);
9986 h = h_next;
9987 }/* end while(h) */
9988
9989 s = p->srv;
9990 while (s) {
9991 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01009992 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01009993 free(s->id);
9994
willy tarreaub952e1d2005-12-18 01:31:20 +01009995 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01009996 free(s->cookie);
9997
9998 free(s);
9999 s = s_next;
10000 }/* end while(s) */
10001
10002 l = p->listen;
10003 while (l) {
10004 l_next = l->next;
10005 free(l);
10006 l = l_next;
10007 }/* end while(l) */
10008
10009 pool_destroy((void **) p->req_cap_pool);
10010 pool_destroy((void **) p->rsp_cap_pool);
10011 p = p->next;
10012 }/* end while(p) */
10013
10014 if (global.chroot) free(global.chroot);
10015 if (global.pidfile) free(global.pidfile);
10016
willy tarreau12350152005-12-18 01:03:27 +010010017 if (StaticReadEvent) free(StaticReadEvent);
10018 if (StaticWriteEvent) free(StaticWriteEvent);
10019 if (fdtab) free(fdtab);
10020
10021 pool_destroy(pool_session);
10022 pool_destroy(pool_buffer);
10023 pool_destroy(pool_fdtab);
10024 pool_destroy(pool_requri);
10025 pool_destroy(pool_task);
10026 pool_destroy(pool_capture);
10027 pool_destroy(pool_appsess);
10028
10029 if (have_appsession) {
10030 pool_destroy(apools.serverid);
10031 pool_destroy(apools.sessid);
10032 }
10033} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +010010034
willy tarreau41310e72006-03-25 18:17:56 +010010035/* sends the signal <sig> to all pids found in <oldpids> */
10036static void tell_old_pids(int sig) {
10037 int p;
10038 for (p = 0; p < nb_oldpids; p++)
10039 kill(oldpids[p], sig);
10040}
10041
willy tarreau0f7af912005-12-17 12:21:26 +010010042int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +010010043 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +010010044 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +010010045 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +010010046 init(argc, argv);
10047
willy tarreau0f7af912005-12-17 12:21:26 +010010048 signal(SIGQUIT, dump);
10049 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +010010050 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +010010051#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +010010052 signal(SIGINT, sig_int);
10053 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +010010054#endif
willy tarreau0f7af912005-12-17 12:21:26 +010010055
10056 /* on very high loads, a sigpipe sometimes happen just between the
10057 * getsockopt() which tells "it's OK to write", and the following write :-(
10058 */
willy tarreau3242e862005-12-17 12:27:53 +010010059#ifndef MSG_NOSIGNAL
10060 signal(SIGPIPE, SIG_IGN);
10061#endif
willy tarreau0f7af912005-12-17 12:21:26 +010010062
willy tarreau41310e72006-03-25 18:17:56 +010010063 /* We will loop at most 100 times with 10 ms delay each time.
10064 * That's at most 1 second. We only send a signal to old pids
10065 * if we cannot grab at least one port.
10066 */
10067 retry = MAX_START_RETRIES;
10068 err = ERR_NONE;
10069 while (retry >= 0) {
10070 struct timeval w;
10071 err = start_proxies(retry == 0 || nb_oldpids == 0);
10072 if (err != ERR_RETRYABLE)
10073 break;
10074 if (nb_oldpids == 0)
10075 break;
10076
Willy TARREAU007aa462006-05-14 09:55:23 +020010077 /* FIXME-20060514: Solaris and OpenBSD do not support shutdown() on
10078 * listening sockets. So on those platforms, it would be wiser to
10079 * simply send SIGUSR1, which will not be undoable.
10080 */
willy tarreau41310e72006-03-25 18:17:56 +010010081 tell_old_pids(SIGTTOU);
10082 /* give some time to old processes to stop listening */
10083 w.tv_sec = 0;
10084 w.tv_usec = 10*1000;
10085 select(0, NULL, NULL, NULL, &w);
10086 retry--;
10087 }
10088
10089 /* Note: start_proxies() sends an alert when it fails. */
10090 if (err != ERR_NONE) {
10091 if (retry != MAX_START_RETRIES && nb_oldpids)
10092 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +010010093 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +010010094 }
willy tarreaud0fb4652005-12-18 01:32:04 +010010095
10096 if (listeners == 0) {
10097 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +010010098 /* Note: we don't have to send anything to the old pids because we
10099 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +010010100 exit(1);
10101 }
10102
willy tarreaudbd3bef2006-01-20 19:35:18 +010010103 /* prepare pause/play signals */
10104 signal(SIGTTOU, sig_pause);
10105 signal(SIGTTIN, sig_listen);
10106
Willy TARREAUe3283d12006-03-01 22:15:29 +010010107 if (global.mode & MODE_DAEMON) {
10108 global.mode &= ~MODE_VERBOSE;
10109 global.mode |= MODE_QUIET;
10110 }
10111
willy tarreaud0fb4652005-12-18 01:32:04 +010010112 /* MODE_QUIET can inhibit alerts and warnings below this line */
10113
10114 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +010010115 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +010010116 /* detach from the tty */
10117 fclose(stdin); fclose(stdout); fclose(stderr);
10118 close(0); close(1); close(2);
10119 }
willy tarreau0f7af912005-12-17 12:21:26 +010010120
willy tarreaufe2c5c12005-12-17 14:14:34 +010010121 /* open log & pid files before the chroot */
10122 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
10123 int pidfd;
10124 unlink(global.pidfile);
10125 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
10126 if (pidfd < 0) {
10127 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +010010128 if (nb_oldpids)
10129 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +010010130 exit(1);
10131 }
10132 pidfile = fdopen(pidfd, "w");
10133 }
willy tarreau9fe663a2005-12-17 13:02:59 +010010134
10135 /* chroot if needed */
10136 if (global.chroot != NULL) {
10137 if (chroot(global.chroot) == -1) {
10138 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +010010139 if (nb_oldpids)
10140 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +010010141 }
10142 chdir("/");
10143 }
10144
willy tarreaub1285d52005-12-18 01:20:14 +010010145 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +010010146 if (!global.rlimit_nofile)
10147 global.rlimit_nofile = global.maxsock;
10148
willy tarreaub1285d52005-12-18 01:20:14 +010010149 if (global.rlimit_nofile) {
10150 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
10151 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
10152 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
10153 }
willy tarreau746e26b2006-03-25 11:14:35 +010010154 }
10155
10156 if (global.rlimit_memmax) {
10157 limit.rlim_cur = limit.rlim_max =
10158 global.rlimit_memmax * 1048576 / global.nbproc;
10159#ifdef RLIMIT_AS
10160 if (setrlimit(RLIMIT_AS, &limit) == -1) {
10161 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
10162 argv[0], global.rlimit_memmax);
10163 }
10164#else
10165 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
10166 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
10167 argv[0], global.rlimit_memmax);
10168 }
10169#endif
willy tarreaub1285d52005-12-18 01:20:14 +010010170 }
10171
willy tarreau41310e72006-03-25 18:17:56 +010010172 if (nb_oldpids)
10173 tell_old_pids(oldpids_sig);
10174
10175 /* Note that any error at this stage will be fatal because we will not
10176 * be able to restart the old pids.
10177 */
10178
willy tarreau9fe663a2005-12-17 13:02:59 +010010179 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +010010180 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +010010181 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
10182 exit(1);
10183 }
10184
willy tarreau036e1ce2005-12-17 13:46:33 +010010185 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +010010186 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
10187 exit(1);
10188 }
10189
willy tarreaub1285d52005-12-18 01:20:14 +010010190 /* check ulimits */
10191 limit.rlim_cur = limit.rlim_max = 0;
10192 getrlimit(RLIMIT_NOFILE, &limit);
10193 if (limit.rlim_cur < global.maxsock) {
10194 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",
10195 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
10196 }
10197
willy tarreau9fe663a2005-12-17 13:02:59 +010010198 if (global.mode & MODE_DAEMON) {
10199 int ret = 0;
10200 int proc;
10201
10202 /* the father launches the required number of processes */
10203 for (proc = 0; proc < global.nbproc; proc++) {
10204 ret = fork();
10205 if (ret < 0) {
10206 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +010010207 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +010010208 exit(1); /* there has been an error */
10209 }
10210 else if (ret == 0) /* child breaks here */
10211 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +010010212 if (pidfile != NULL) {
10213 fprintf(pidfile, "%d\n", ret);
10214 fflush(pidfile);
10215 }
willy tarreau9fe663a2005-12-17 13:02:59 +010010216 }
willy tarreaufe2c5c12005-12-17 14:14:34 +010010217 /* close the pidfile both in children and father */
10218 if (pidfile != NULL)
10219 fclose(pidfile);
10220 free(global.pidfile);
10221
willy tarreau9fe663a2005-12-17 13:02:59 +010010222 if (proc == global.nbproc)
10223 exit(0); /* parent must leave */
10224
willy tarreau750a4722005-12-17 13:21:24 +010010225 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
10226 * that we can detach from the TTY. We MUST NOT do it in other cases since
10227 * it would have already be done, and 0-2 would have been affected to listening
10228 * sockets
10229 */
10230 if (!(global.mode & MODE_QUIET)) {
10231 /* detach from the tty */
10232 fclose(stdin); fclose(stdout); fclose(stderr);
10233 close(0); close(1); close(2); /* close all fd's */
10234 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
10235 }
willy tarreaua1598082005-12-17 13:08:06 +010010236 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +010010237 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +010010238 }
10239
willy tarreau1c2ad212005-12-18 01:11:29 +010010240#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +010010241 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010242 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
10243 epoll_loop(POLL_LOOP_ACTION_RUN);
10244 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010245 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010246 }
10247 else {
willy tarreau64a3cc32005-12-18 01:13:11 +010010248 Warning("epoll() is not available. Using poll()/select() instead.\n");
10249 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010250 }
10251 }
10252#endif
10253
10254#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +010010255 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010256 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
10257 poll_loop(POLL_LOOP_ACTION_RUN);
10258 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010259 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010260 }
10261 else {
10262 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +010010263 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010264 }
10265 }
10266#endif
willy tarreau64a3cc32005-12-18 01:13:11 +010010267 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010268 if (select_loop(POLL_LOOP_ACTION_INIT)) {
10269 select_loop(POLL_LOOP_ACTION_RUN);
10270 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010271 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +010010272 }
10273 }
10274
willy tarreau0f7af912005-12-17 12:21:26 +010010275
willy tarreau12350152005-12-18 01:03:27 +010010276 /* Free all Hash Keys and all Hash elements */
10277 appsession_cleanup();
10278 /* Do some cleanup */
10279 deinit();
10280
willy tarreau0f7af912005-12-17 12:21:26 +010010281 exit(0);
10282}
willy tarreau12350152005-12-18 01:03:27 +010010283
10284#if defined(DEBUG_HASH)
10285static void print_table(const CHTbl *htbl) {
10286
10287 ListElmt *element;
10288 int i;
10289 appsess *asession;
10290
10291 /*****************************************************************************
10292 * *
10293 * Display the chained hash table. *
10294 * *
10295 *****************************************************************************/
10296
10297 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
10298
10299 for (i = 0; i < TBLSIZ; i++) {
10300 fprintf(stdout, "Bucket[%03d]\n", i);
10301
10302 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
10303 //fprintf(stdout, "%c", *(char *)list_data(element));
10304 asession = (appsess *)list_data(element);
10305 fprintf(stdout, "ELEM :%s:", asession->sessid);
10306 fprintf(stdout, " Server :%s: \n", asession->serverid);
10307 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
10308 }
10309
10310 fprintf(stdout, "\n");
10311 }
10312 return;
10313} /* end print_table */
10314#endif
10315
10316static int appsession_init(void)
10317{
10318 static int initialized = 0;
10319 int idlen;
10320 struct server *s;
10321 struct proxy *p = proxy;
10322
10323 if (!initialized) {
10324 if (!appsession_task_init()) {
10325 apools.sessid = NULL;
10326 apools.serverid = NULL;
10327 apools.ser_waste = 0;
10328 apools.ser_use = 0;
10329 apools.ser_msize = sizeof(void *);
10330 apools.ses_waste = 0;
10331 apools.ses_use = 0;
10332 apools.ses_msize = sizeof(void *);
10333 while (p) {
10334 s = p->srv;
10335 if (apools.ses_msize < p->appsession_len)
10336 apools.ses_msize = p->appsession_len;
10337 while (s) {
10338 idlen = strlen(s->id);
10339 if (apools.ser_msize < idlen)
10340 apools.ser_msize = idlen;
10341 s = s->next;
10342 }
10343 p = p->next;
10344 }
10345 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
10346 apools.ses_msize ++;
10347 }
10348 else {
10349 fprintf(stderr, "appsession_task_init failed\n");
10350 return -1;
10351 }
10352 initialized ++;
10353 }
10354 return 0;
10355}
10356
10357static int appsession_task_init(void)
10358{
10359 static int initialized = 0;
10360 struct task *t;
10361 if (!initialized) {
10362 if ((t = pool_alloc(task)) == NULL)
10363 return -1;
10364 t->next = t->prev = t->rqnext = NULL;
willy tarreau5e698ef2006-05-02 14:51:00 +020010365 t->wq = LIST_HEAD(wait_queue[0]);
willy tarreau12350152005-12-18 01:03:27 +010010366 t->state = TASK_IDLE;
10367 t->context = NULL;
10368 tv_delayfrom(&t->expire, &now, TBLCHKINT);
10369 task_queue(t);
10370 t->process = appsession_refresh;
10371 initialized ++;
10372 }
10373 return 0;
10374}
10375
10376static int appsession_refresh(struct task *t) {
10377 struct proxy *p = proxy;
10378 CHTbl *htbl;
10379 ListElmt *element, *last;
10380 int i;
10381 appsess *asession;
10382 void *data;
10383
10384 while (p) {
10385 if (p->appsession_name != NULL) {
10386 htbl = &p->htbl_proxy;
10387 /* if we ever give up the use of TBLSIZ, we need to change this */
10388 for (i = 0; i < TBLSIZ; i++) {
10389 last = NULL;
10390 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
10391 asession = (appsess *)list_data(element);
10392 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
10393 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
10394 int len;
10395 /*
10396 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
10397 */
10398 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
10399 asession->sessid, asession->serverid?asession->serverid:"(null)");
10400 write(1, trash, len);
10401 }
10402 /* delete the expired element from within the hash table */
10403 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
10404 && (htbl->table[i].destroy != NULL)) {
10405 htbl->table[i].destroy(data);
10406 }
10407 if (last == NULL) {/* patient lost his head, get a new one */
10408 element = list_head(&htbl->table[i]);
10409 if (element == NULL) break; /* no heads left, go to next patient */
10410 }
10411 else
10412 element = last;
10413 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
10414 else
10415 last = element;
10416 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
10417 }
10418 }
10419 p = p->next;
10420 }
10421 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
10422 return TBLCHKINT;
10423} /* end appsession_refresh */
10424
willy tarreau18a957c2006-04-12 19:26:23 +020010425
10426/*
10427 * Local variables:
10428 * c-indent-level: 4
10429 * c-basic-offset: 4
10430 * End:
10431 */