blob: 2372c6b0b5388493c4a2647f901884c6fef739fe [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 tarreau598da412005-12-18 01:07:29 +010088#include "include/appsession.h"
willy tarreau18a957c2006-04-12 19:26:23 +020089#include "include/mini-clist.h"
willy tarreau12350152005-12-18 01:03:27 +010090
willy tarreaubfad5742006-03-23 14:19:11 +010091#ifndef HAPROXY_VERSION
willy tarreauc3a2e072006-05-13 18:51:38 +020092#define HAPROXY_VERSION "1.2.13"
willy tarreaubfad5742006-03-23 14:19:11 +010093#endif
94
95#ifndef HAPROXY_DATE
willy tarreauc3a2e072006-05-13 18:51:38 +020096#define HAPROXY_DATE "2006/05/13"
willy tarreaubfad5742006-03-23 14:19:11 +010097#endif
willy tarreau0f7af912005-12-17 12:21:26 +010098
99/* this is for libc5 for example */
100#ifndef TCP_NODELAY
101#define TCP_NODELAY 1
102#endif
103
104#ifndef SHUT_RD
105#define SHUT_RD 0
106#endif
107
108#ifndef SHUT_WR
109#define SHUT_WR 1
110#endif
111
willy tarreau0174f312005-12-18 01:02:42 +0100112/*
113 * BUFSIZE defines the size of a read and write buffer. It is the maximum
114 * amount of bytes which can be stored by the proxy for each session. However,
115 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
116 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
117 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
118 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
119 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
120 */
121#ifndef BUFSIZE
122#define BUFSIZE 16384
123#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100124
125// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100126#ifndef MAXREWRITE
127#define MAXREWRITE (BUFSIZE / 2)
128#endif
129
willy tarreau9fe663a2005-12-17 13:02:59 +0100130#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100131#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100132
willy tarreau5cbea6f2005-12-17 12:48:26 +0100133// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100134#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100135
willy tarreaue39cd132005-12-17 13:00:18 +0100136// max # of added headers per request
137#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100138
139// max # of matches per regexp
140#define MAX_MATCH 10
141
willy tarreau0174f312005-12-18 01:02:42 +0100142// cookie delimitor in "prefix" mode. This character is inserted between the
143// persistence cookie and the original value. The '~' is allowed by RFC2965,
144// and should not be too common in server names.
145#ifndef COOKIE_DELIM
146#define COOKIE_DELIM '~'
147#endif
148
willy tarreau0f7af912005-12-17 12:21:26 +0100149#define CONN_RETRIES 3
150
willy tarreau5cbea6f2005-12-17 12:48:26 +0100151#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100152#define DEF_CHKINTR 2000
153#define DEF_FALLTIME 3
154#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100155#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100156
Willy TARREAU13032e72006-03-12 17:31:45 +0100157/* Default connections limit.
158 *
159 * A system limit can be enforced at build time in order to avoid using haproxy
160 * beyond reasonable system limits. For this, just define SYSTEM_MAXCONN to the
161 * absolute limit accepted by the system. If the configuration specifies a
162 * higher value, it will be capped to SYSTEM_MAXCONN and a warning will be
163 * emitted. The only way to override this limit will be to set it via the
164 * command-line '-n' argument.
165 */
166#ifndef SYSTEM_MAXCONN
willy tarreau9fe663a2005-12-17 13:02:59 +0100167#define DEFAULT_MAXCONN 2000
Willy TARREAU13032e72006-03-12 17:31:45 +0100168#else
169#define DEFAULT_MAXCONN SYSTEM_MAXCONN
170#endif
willy tarreau9fe663a2005-12-17 13:02:59 +0100171
willy tarreau0f7af912005-12-17 12:21:26 +0100172/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
173#define INTBITS 5
174
175/* show stats this every millisecond, 0 to disable */
176#ifndef STATTIME
177#define STATTIME 2000
178#endif
179
willy tarreau5cbea6f2005-12-17 12:48:26 +0100180/* this reduces the number of calls to select() by choosing appropriate
181 * sheduler precision in milliseconds. It should be near the minimum
182 * time that is needed by select() to collect all events. All timeouts
183 * are rounded up by adding this value prior to pass it to select().
184 */
185#define SCHEDULER_RESOLUTION 9
186
willy tarreaub952e1d2005-12-18 01:31:20 +0100187#define TIME_ETERNITY -1
188/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100189#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
190#define SETNOW(a) (*a=now)
191
willy tarreau9da061b2005-12-17 12:29:56 +0100192/****** string-specific macros and functions ******/
193/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
194#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
195
196/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
197#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
198
willy tarreau0174f312005-12-18 01:02:42 +0100199/* returns 1 only if only zero or one bit is set in X, which means that X is a
200 * power of 2, and 0 otherwise */
201#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100202/*
203 * copies at most <size-1> chars from <src> to <dst>. Last char is always
204 * set to 0, unless <size> is 0. The number of chars copied is returned
205 * (excluding the terminating zero).
206 * This code has been optimized for size and speed : on x86, it's 45 bytes
207 * long, uses only registers, and consumes only 4 cycles per char.
208 */
willy tarreau750a4722005-12-17 13:21:24 +0100209int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100210 char *orig = dst;
211 if (size) {
212 while (--size && (*dst = *src)) {
213 src++; dst++;
214 }
215 *dst = 0;
216 }
217 return dst - orig;
218}
willy tarreau9da061b2005-12-17 12:29:56 +0100219
willy tarreau4302f492005-12-18 01:00:37 +0100220/*
221 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
222 * dynamically allocated. In the first case, <__pool> is updated to point to
223 * the next element in the list.
224 */
225#define pool_alloc_from(__pool, __len) ({ \
226 void *__p; \
227 if ((__p = (__pool)) == NULL) \
228 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
229 else { \
230 __pool = *(void **)(__pool); \
231 } \
232 __p; \
233})
234
235/*
236 * Puts a memory area back to the corresponding pool.
237 * Items are chained directly through a pointer that
238 * is written in the beginning of the memory area, so
239 * there's no need for any carrier cell. This implies
240 * that each memory area is at least as big as one
241 * pointer.
242 */
243#define pool_free_to(__pool, __ptr) ({ \
244 *(void **)(__ptr) = (void *)(__pool); \
245 __pool = (void *)(__ptr); \
246})
247
248
willy tarreau0f7af912005-12-17 12:21:26 +0100249#define MEM_OPTIM
250#ifdef MEM_OPTIM
251/*
252 * Returns a pointer to type <type> taken from the
253 * pool <pool_type> or dynamically allocated. In the
254 * first case, <pool_type> is updated to point to the
255 * next element in the list.
256 */
257#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100258 void *__p; \
259 if ((__p = pool_##type) == NULL) \
260 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100261 else { \
262 pool_##type = *(void **)pool_##type; \
263 } \
willy tarreau4302f492005-12-18 01:00:37 +0100264 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100265})
266
267/*
268 * Puts a memory area back to the corresponding pool.
269 * Items are chained directly through a pointer that
270 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100271 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100272 * that each memory area is at least as big as one
273 * pointer.
274 */
275#define pool_free(type, ptr) ({ \
276 *(void **)ptr = (void *)pool_##type; \
277 pool_##type = (void *)ptr; \
278})
279
280#else
281#define pool_alloc(type) (calloc(1,sizeof_##type));
282#define pool_free(type, ptr) (free(ptr));
283#endif /* MEM_OPTIM */
284
willy tarreau5cbea6f2005-12-17 12:48:26 +0100285#define sizeof_task sizeof(struct task)
286#define sizeof_session sizeof(struct session)
willy tarreau18a957c2006-04-12 19:26:23 +0200287#define sizeof_pendconn sizeof(struct pendconn)
willy tarreau0f7af912005-12-17 12:21:26 +0100288#define sizeof_buffer sizeof(struct buffer)
289#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100290#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100291#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100292#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100293#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100294
willy tarreau5cbea6f2005-12-17 12:48:26 +0100295/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100296#define FD_STCLOSE 0
297#define FD_STLISTEN 1
298#define FD_STCONN 2
299#define FD_STREADY 3
300#define FD_STERROR 4
301
willy tarreau5cbea6f2005-12-17 12:48:26 +0100302/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100303#define TASK_IDLE 0
304#define TASK_RUNNING 1
305
willy tarreau5cbea6f2005-12-17 12:48:26 +0100306/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100307#define PR_STNEW 0
308#define PR_STIDLE 1
309#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100310#define PR_STSTOPPED 3
311#define PR_STPAUSED 4
willy tarreau0f7af912005-12-17 12:21:26 +0100312
willy tarreau5cbea6f2005-12-17 12:48:26 +0100313/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100314#define PR_MODE_TCP 0
315#define PR_MODE_HTTP 1
316#define PR_MODE_HEALTH 2
317
willy tarreau1c2ad212005-12-18 01:11:29 +0100318/* possible actions for the *poll() loops */
319#define POLL_LOOP_ACTION_INIT 0
320#define POLL_LOOP_ACTION_RUN 1
321#define POLL_LOOP_ACTION_CLEAN 2
322
willy tarreau64a3cc32005-12-18 01:13:11 +0100323/* poll mechanisms available */
324#define POLL_USE_SELECT (1<<0)
325#define POLL_USE_POLL (1<<1)
326#define POLL_USE_EPOLL (1<<2)
327
willy tarreau5cbea6f2005-12-17 12:48:26 +0100328/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100329#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
330#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
331#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
332#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
333#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
334#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
335#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
336#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau0174f312005-12-18 01:02:42 +0100337#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
338#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
339#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
340#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
341#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
342#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
343#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
344#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
345#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
346#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
347#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100348#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
349#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100350#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100351#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau1a3442d2006-03-24 21:03:20 +0100352#define PR_O_BALANCE_SH 0x00400000 /* balance on source IP hash */
353#define PR_O_BALANCE (PR_O_BALANCE_RR | PR_O_BALANCE_SH)
willy tarreau5cbea6f2005-12-17 12:48:26 +0100354
willy tarreaua5e8c662006-04-29 10:43:46 +0200355/* various session flags, bits values 0x01 to 0x20 (shift 0) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100356#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
357#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
358#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
359#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
360#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
361#define SN_POST 0x00000020 /* the request was an HTTP POST */
362
willy tarreaua5e8c662006-04-29 10:43:46 +0200363/* session flags dedicated to cookies : bits values 0x40, 0x80 (0-3 shift 6) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100364#define SN_CK_NONE 0x00000000 /* this session had no cookie */
365#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
366#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
367#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
368#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
369#define SN_CK_SHIFT 6 /* bit shift */
370
willy tarreaua5e8c662006-04-29 10:43:46 +0200371/* session termination conditions, bits values 0x100 to 0x700 (0-7 shift 8) */
willy tarreaub1285d52005-12-18 01:20:14 +0100372#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100373#define SN_ERR_CLITO 0x00000100 /* client time-out */
374#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
375#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
376#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
377#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100378#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
379#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100380#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
381#define SN_ERR_SHIFT 8 /* bit shift */
382
willy tarreaua5e8c662006-04-29 10:43:46 +0200383/* session state at termination, bits values 0x1000 to 0x7000 (0-7 shift 12) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100384#define SN_FINST_R 0x00001000 /* session ended during client request */
385#define SN_FINST_C 0x00002000 /* session ended during server connect */
386#define SN_FINST_H 0x00003000 /* session ended during server headers */
387#define SN_FINST_D 0x00004000 /* session ended during data phase */
388#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
willy tarreau078c79a2006-05-13 12:23:58 +0200389#define SN_FINST_Q 0x00006000 /* session ended while waiting in queue for a server slot */
willy tarreau036e1ce2005-12-17 13:46:33 +0100390#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
391#define SN_FINST_SHIFT 12 /* bit shift */
392
willy tarreaua5e8c662006-04-29 10:43:46 +0200393/* cookie information, bits values 0x10000 to 0x80000 (0-8 shift 16) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100394#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
395#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
396#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
397#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
398#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100399#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100400#define SN_SCK_SHIFT 16 /* bit shift */
401
willy tarreaua5e8c662006-04-29 10:43:46 +0200402/* cacheability management, bits values 0x100000 to 0x300000 (0-3 shift 20) */
willy tarreau97f58572005-12-18 00:53:44 +0100403#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
404#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
405#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100406
willy tarreaua5e8c662006-04-29 10:43:46 +0200407/* various other session flags, bits values 0x400000 and above */
408#define SN_MONITOR 0x00400000 /* this session comes from a monitoring system */
willy tarreaudfece232006-05-02 00:19:57 +0200409#define SN_ASSIGNED 0x00800000 /* no need to assign a server to this session */
410#define SN_ADDR_SET 0x01000000 /* this session's server address has been set */
willy tarreaua5e8c662006-04-29 10:43:46 +0200411
412
willy tarreau5cbea6f2005-12-17 12:48:26 +0100413/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100414#define CL_STHEADERS 0
415#define CL_STDATA 1
416#define CL_STSHUTR 2
417#define CL_STSHUTW 3
418#define CL_STCLOSE 4
419
willy tarreau5cbea6f2005-12-17 12:48:26 +0100420/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100421#define SV_STIDLE 0
willy tarreau9fea1942006-05-12 19:46:40 +0200422#define SV_STCONN 1
423#define SV_STHEADERS 2
424#define SV_STDATA 3
425#define SV_STSHUTR 4
426#define SV_STSHUTW 5
427#define SV_STCLOSE 6
willy tarreau0f7af912005-12-17 12:21:26 +0100428
429/* result of an I/O event */
430#define RES_SILENT 0 /* didn't happen */
431#define RES_DATA 1 /* data were sent or received */
432#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
433#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
434
willy tarreau9fe663a2005-12-17 13:02:59 +0100435/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100436#define MODE_DEBUG 1
437#define MODE_STATS 2
438#define MODE_LOG 4
439#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100440#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100441#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100442#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100443#define MODE_STARTING 128
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100444#define MODE_FOREGROUND 256
willy tarreau5cbea6f2005-12-17 12:48:26 +0100445
446/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100447#define SRV_RUNNING 1 /* the server is UP */
448#define SRV_BACKUP 2 /* this server is a backup server */
449#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100450#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100451#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100452
willy tarreaudfece232006-05-02 00:19:57 +0200453/* function which act on servers need to return various errors */
454#define SRV_STATUS_OK 0 /* everything is OK. */
455#define SRV_STATUS_INTERNAL 1 /* other unrecoverable errors. */
456#define SRV_STATUS_NOSRV 2 /* no server is available */
457#define SRV_STATUS_FULL 3 /* the/all server(s) are saturated */
458#define SRV_STATUS_QUEUED 4 /* the/all server(s) are saturated but the connection was queued */
459
willy tarreaue39cd132005-12-17 13:00:18 +0100460/* what to do when a header matches a regex */
461#define ACT_ALLOW 0 /* allow the request */
462#define ACT_REPLACE 1 /* replace the matching header */
463#define ACT_REMOVE 2 /* remove the matching header */
464#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100465#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100466
willy tarreau9fe663a2005-12-17 13:02:59 +0100467/* configuration sections */
468#define CFG_NONE 0
469#define CFG_GLOBAL 1
470#define CFG_LISTEN 2
471
willy tarreaua1598082005-12-17 13:08:06 +0100472/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100473#define LW_DATE 1 /* date */
474#define LW_CLIP 2 /* CLient IP */
475#define LW_SVIP 4 /* SerVer IP */
476#define LW_SVID 8 /* server ID */
477#define LW_REQ 16 /* http REQuest */
478#define LW_RESP 32 /* http RESPonse */
479#define LW_PXIP 64 /* proxy IP */
480#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100481#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100482#define LW_COOKIE 512 /* captured cookie */
483#define LW_REQHDR 1024 /* request header(s) */
484#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100485
willy tarreau41310e72006-03-25 18:17:56 +0100486#define ERR_NONE 0 /* no error */
487#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
488#define ERR_FATAL 2 /* fatal error, may be cumulated */
489
willy tarreau0f7af912005-12-17 12:21:26 +0100490/*********************************************************************/
491
492#define LIST_HEAD(a) ((void *)(&(a)))
493
494/*********************************************************************/
495
willy tarreau4302f492005-12-18 01:00:37 +0100496struct cap_hdr {
497 struct cap_hdr *next;
498 char *name; /* header name, case insensitive */
499 int namelen; /* length of the header name, to speed-up lookups */
500 int len; /* capture length, not including terminal zero */
501 int index; /* index in the output array */
502 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
503};
504
willy tarreau0f7af912005-12-17 12:21:26 +0100505struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100506 struct hdr_exp *next;
507 regex_t *preg; /* expression to look for */
508 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
509 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100510};
511
512struct buffer {
513 unsigned int l; /* data length */
514 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100515 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100516 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100517 char data[BUFSIZE];
518};
519
willy tarreau18a957c2006-04-12 19:26:23 +0200520struct pendconn {
521 struct list list; /* chaining ... */
522 struct session *sess; /* the session waiting for a connection */
523 struct server *srv; /* the server we are waiting for */
524};
525
willy tarreau0f7af912005-12-17 12:21:26 +0100526struct server {
527 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100528 int state; /* server state (SRV_*) */
529 int cklen; /* the len of the cookie, to speed up checks */
530 char *cookie; /* the id set in the cookie */
531 char *id; /* just for identification */
willy tarreau18a957c2006-04-12 19:26:23 +0200532 struct list pendconns; /* pending connections */
533 int nbpend; /* number of pending connections */
willy tarreau59a6cc22006-05-12 01:29:08 +0200534 struct task *queue_mgt; /* the task associated to the queue processing */
willy tarreau0f7af912005-12-17 12:21:26 +0100535 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100536 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100537 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100538 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100539 int rise, fall; /* time in iterations */
540 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100541 int result; /* 0 = connect OK, -1 = connect KO */
542 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreaue3f023f2006-04-08 21:52:24 +0200543 unsigned char uweight, eweight; /* user-specified weight-1, and effective weight-1 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200544 unsigned int wscore; /* weight score, used during srv map computation */
willy tarreaua647c702006-04-15 22:45:52 +0200545 int cur_sess; /* number of currently active sessions (including syn_sent) */
546 unsigned int cum_sess; /* cumulated number of sessions really sent to this server */
willy tarreau18a957c2006-04-12 19:26:23 +0200547 unsigned int maxconn; /* max # of active sessions. 0 = unlimited. */
willy tarreau535ae7a2005-12-17 12:58:00 +0100548 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100549};
550
willy tarreau5cbea6f2005-12-17 12:48:26 +0100551/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100552struct task {
553 struct task *next, *prev; /* chaining ... */
554 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100555 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100556 int state; /* task state : IDLE or RUNNING */
557 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100558 int (*process)(struct task *t); /* the function which processes the task */
559 void *context; /* the task's context */
560};
561
562/* WARNING: if new fields are added, they must be initialized in event_accept() */
563struct session {
564 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100565 /* application specific below */
566 struct timeval crexpire; /* expiration date for a client read */
567 struct timeval cwexpire; /* expiration date for a client write */
568 struct timeval srexpire; /* expiration date for a server read */
569 struct timeval swexpire; /* expiration date for a server write */
570 struct timeval cnexpire; /* expiration date for a connect */
571 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
572 struct proxy *proxy; /* the proxy this socket belongs to */
573 int cli_fd; /* the client side fd */
574 int srv_fd; /* the server side fd */
575 int cli_state; /* state of the client side */
576 int srv_state; /* state of the server side */
577 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100578 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100579 struct buffer *req; /* request buffer */
580 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100581 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100582 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100583 struct server *srv; /* the server being used */
willy tarreau18a957c2006-04-12 19:26:23 +0200584 struct pendconn *pend_pos; /* if not NULL, points to the position in the pending queue */
willy tarreau4302f492005-12-18 01:00:37 +0100585 char **req_cap; /* array of captured request headers (may be NULL) */
586 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100587 struct {
588 int logwait; /* log fields waiting to be collected : LW_* */
589 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
590 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
willy tarreauf32f5242006-05-02 22:54:52 +0200591 long t_queue; /* delay before the session gets out of the connect queue, -1 if never occurs */
willy tarreaua1598082005-12-17 13:08:06 +0100592 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
593 long t_data; /* delay before the first data byte from the server ... */
594 unsigned long t_close; /* total session duration */
willy tarreau5e69b162006-05-12 19:49:37 +0200595 unsigned long srv_queue_size; /* number of sessions waiting for a connect slot on this server at accept() time (in direct assignment) */
596 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 +0100597 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100598 char *cli_cookie; /* cookie presented by the client, in capture mode */
599 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100600 int status; /* HTTP status from the server, negative if from proxy */
601 long long bytes; /* number of bytes transferred from the server */
602 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100603 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100604};
605
willy tarreaua41a8b42005-12-17 14:02:24 +0100606struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100607 int fd; /* the listen socket */
608 struct sockaddr_storage addr; /* the address we listen to */
609 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100610};
willy tarreauf32f5242006-05-02 22:54:52 +0200611
willy tarreau0f7af912005-12-17 12:21:26 +0100612struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100613 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100614 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 +0100615 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100616 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200617 struct server *srv; /* known servers */
618 int srv_act, srv_bck; /* # of running servers */
619 int tot_wact, tot_wbck; /* total weights of active and backup servers */
620 struct server **srv_map; /* the server map used to apply weights */
621 int srv_map_sz; /* the size of the effective server map */
622 int srv_rr_idx; /* next server to be elected in round robin mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100623 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100624 int cookie_len; /* strlen(cookie_name), computed only once */
625 char *appsession_name; /* name of the cookie to look for */
626 int appsession_name_len; /* strlen(appsession_name), computed only once */
627 int appsession_len; /* length of the appsession cookie value to be used */
628 int appsession_timeout;
629 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100630 char *capture_name; /* beginning of the name of the cookie to capture */
631 int capture_namelen; /* length of the cookie name to match */
632 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100633 int clitimeout; /* client I/O timeout (in milliseconds) */
634 int srvtimeout; /* server I/O timeout (in milliseconds) */
635 int contimeout; /* connect timeout (in milliseconds) */
636 char *id; /* proxy id */
willy tarreaudfece232006-05-02 00:19:57 +0200637 struct list pendconns; /* pending connections with no server assigned yet */
638 int nbpend; /* number of pending connections with no server assigned yet */
willy tarreauf32f5242006-05-02 22:54:52 +0200639 int totpend; /* total number of pending connections on this instance (for stats) */
willy tarreau0f7af912005-12-17 12:21:26 +0100640 int nbconn; /* # of active sessions */
willy tarreau14b4d432006-04-07 18:23:29 +0200641 unsigned int cum_conn; /* cumulated number of processed sessions */
willy tarreau0f7af912005-12-17 12:21:26 +0100642 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100643 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100644 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100645 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100646 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100647 struct proxy *next;
648 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100649 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100650 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100651 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100652 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100653 int nb_reqadd, nb_rspadd;
654 struct hdr_exp *req_exp; /* regular expressions for request headers */
655 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100656 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
657 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
658 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
659 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100660 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100661 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100662 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
663 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100664 struct {
665 char *msg400; /* message for error 400 */
666 int len400; /* message length for error 400 */
667 char *msg403; /* message for error 403 */
668 int len403; /* message length for error 403 */
669 char *msg408; /* message for error 408 */
670 int len408; /* message length for error 408 */
671 char *msg500; /* message for error 500 */
672 int len500; /* message length for error 500 */
673 char *msg502; /* message for error 502 */
674 int len502; /* message length for error 502 */
675 char *msg503; /* message for error 503 */
676 int len503; /* message length for error 503 */
677 char *msg504; /* message for error 504 */
678 int len504; /* message length for error 504 */
679 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100680};
681
682/* info about one given fd */
683struct fdtab {
684 int (*read)(int fd); /* read function */
685 int (*write)(int fd); /* write function */
686 struct task *owner; /* the session (or proxy) associated with this fd */
687 int state; /* the state of this fd */
688};
689
690/*********************************************************************/
691
willy tarreaub952e1d2005-12-18 01:31:20 +0100692int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100693int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100694char *cfg_cfgfile = NULL; /* configuration file */
695char *progname = NULL; /* program name */
696int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100697
698/* global options */
699static struct {
700 int uid;
701 int gid;
702 int nbproc;
703 int maxconn;
704 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100705 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100706 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100707 int mode;
708 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100709 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100710 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100711 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100712 struct sockaddr_in logsrv1, logsrv2;
713} global = {
714 logfac1 : -1,
715 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100716 loglev1 : 7, /* max syslog level : debug */
717 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100718 /* others NULL OK */
719};
720
willy tarreau0f7af912005-12-17 12:21:26 +0100721/*********************************************************************/
722
willy tarreau1c2ad212005-12-18 01:11:29 +0100723fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100724 *StaticWriteEvent;
725
willy tarreau64a3cc32005-12-18 01:13:11 +0100726int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100727
willy tarreau0f7af912005-12-17 12:21:26 +0100728void **pool_session = NULL,
willy tarreau18a957c2006-04-12 19:26:23 +0200729 **pool_pendconn = NULL,
willy tarreau0f7af912005-12-17 12:21:26 +0100730 **pool_buffer = NULL,
731 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100732 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100733 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100734 **pool_capture = NULL,
735 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100736
737struct proxy *proxy = NULL; /* list of all existing proxies */
738struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100739struct task *rq = NULL; /* global run queue */
willy tarreau5e698ef2006-05-02 14:51:00 +0200740struct task wait_queue[2] = { /* global wait queue */
741 {
742 prev:LIST_HEAD(wait_queue[0]), /* expirable tasks */
743 next:LIST_HEAD(wait_queue[0]),
744 },
745 {
746 prev:LIST_HEAD(wait_queue[1]), /* non-expirable tasks */
747 next:LIST_HEAD(wait_queue[1]),
748 },
willy tarreau5cbea6f2005-12-17 12:48:26 +0100749};
willy tarreau0f7af912005-12-17 12:21:26 +0100750
willy tarreau0f7af912005-12-17 12:21:26 +0100751static int totalconn = 0; /* total # of terminated sessions */
752static int actconn = 0; /* # of active sessions */
753static int maxfd = 0; /* # of the highest fd + 1 */
754static int listeners = 0; /* # of listeners */
755static int stopping = 0; /* non zero means stopping in progress */
756static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100757static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100758
willy tarreau53e99702006-03-25 18:53:50 +0100759/* Here we store informations about the pids of the processes we may pause
760 * or kill. We will send them a signal every 10 ms until we can bind to all
761 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100762 */
willy tarreau53e99702006-03-25 18:53:50 +0100763#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100764static int nb_oldpids = 0;
765static int *oldpids = NULL;
766static int oldpids_sig; /* use USR1 or TERM */
767
willy tarreau08dedbe2005-12-18 01:13:48 +0100768#if defined(ENABLE_EPOLL)
769/* FIXME: this is dirty, but at the moment, there's no other solution to remove
770 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
771 * structure with pointers to functions such as init_fd() and close_fd(), plus
772 * a private structure with several pointers to places such as below.
773 */
774
775static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
776#endif
777
willy tarreau0f7af912005-12-17 12:21:26 +0100778static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100779/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100780static char trash[BUFSIZE];
781
willy tarreaudd07e972005-12-18 00:48:48 +0100782const int zero = 0;
783const int one = 1;
784
willy tarreau0f7af912005-12-17 12:21:26 +0100785/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100786 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100787 */
788
789#define MAX_SYSLOG_LEN 1024
790#define NB_LOG_FACILITIES 24
791const char *log_facilities[NB_LOG_FACILITIES] = {
792 "kern", "user", "mail", "daemon",
793 "auth", "syslog", "lpr", "news",
794 "uucp", "cron", "auth2", "ftp",
795 "ntp", "audit", "alert", "cron2",
796 "local0", "local1", "local2", "local3",
797 "local4", "local5", "local6", "local7"
798};
799
800
801#define NB_LOG_LEVELS 8
802const char *log_levels[NB_LOG_LEVELS] = {
803 "emerg", "alert", "crit", "err",
804 "warning", "notice", "info", "debug"
805};
806
807#define SYSLOG_PORT 514
808
809const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
810 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100811
willy tarreaub1285d52005-12-18 01:20:14 +0100812const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau078c79a2006-05-13 12:23:58 +0200813const char sess_fin_state[8] = "-RCHDLQ7"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, unknown */
willy tarreau036e1ce2005-12-17 13:46:33 +0100814const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
815const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
816 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
817 unknown, Set-cookie Rewritten */
818
willy tarreau0f7af912005-12-17 12:21:26 +0100819#define MAX_HOSTNAME_LEN 32
820static char hostname[MAX_HOSTNAME_LEN] = "";
821
willy tarreau8337c6b2005-12-17 13:41:01 +0100822const char *HTTP_302 =
823 "HTTP/1.0 302 Found\r\n"
824 "Cache-Control: no-cache\r\n"
825 "Connection: close\r\n"
826 "Location: "; /* not terminated since it will be concatenated with the URL */
827
willy tarreauc1f47532005-12-18 01:08:26 +0100828/* same as 302 except that the browser MUST retry with the GET method */
829const char *HTTP_303 =
830 "HTTP/1.0 303 See Other\r\n"
831 "Cache-Control: no-cache\r\n"
832 "Connection: close\r\n"
833 "Location: "; /* not terminated since it will be concatenated with the URL */
834
willy tarreaua1598082005-12-17 13:08:06 +0100835const char *HTTP_400 =
836 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100837 "Cache-Control: no-cache\r\n"
838 "Connection: close\r\n"
839 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100840 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100841
willy tarreaua1598082005-12-17 13:08:06 +0100842const char *HTTP_403 =
843 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100844 "Cache-Control: no-cache\r\n"
845 "Connection: close\r\n"
846 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100847 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
848
willy tarreau8337c6b2005-12-17 13:41:01 +0100849const char *HTTP_408 =
850 "HTTP/1.0 408 Request Time-out\r\n"
851 "Cache-Control: no-cache\r\n"
852 "Connection: close\r\n"
853 "\r\n"
854 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
855
willy tarreau750a4722005-12-17 13:21:24 +0100856const char *HTTP_500 =
857 "HTTP/1.0 500 Server Error\r\n"
858 "Cache-Control: no-cache\r\n"
859 "Connection: close\r\n"
860 "\r\n"
861 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100862
863const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100864 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100865 "Cache-Control: no-cache\r\n"
866 "Connection: close\r\n"
867 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100868 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
869
870const char *HTTP_503 =
871 "HTTP/1.0 503 Service Unavailable\r\n"
872 "Cache-Control: no-cache\r\n"
873 "Connection: close\r\n"
874 "\r\n"
875 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
876
877const char *HTTP_504 =
878 "HTTP/1.0 504 Gateway Time-out\r\n"
879 "Cache-Control: no-cache\r\n"
880 "Connection: close\r\n"
881 "\r\n"
882 "<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 +0100883
willy tarreau0f7af912005-12-17 12:21:26 +0100884/*********************************************************************/
885/* statistics ******************************************************/
886/*********************************************************************/
887
willy tarreau750a4722005-12-17 13:21:24 +0100888#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100889static int stats_tsk_lsrch, stats_tsk_rsrch,
890 stats_tsk_good, stats_tsk_right, stats_tsk_left,
891 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100892#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100893
894
895/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100896/* debugging *******************************************************/
897/*********************************************************************/
898#ifdef DEBUG_FULL
899static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau18a957c2006-04-12 19:26:23 +0200900static char *srv_stnames[8] = {"IDL", "PND", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau750a4722005-12-17 13:21:24 +0100901#endif
902
903/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100904/* function prototypes *********************************************/
905/*********************************************************************/
906
907int event_accept(int fd);
908int event_cli_read(int fd);
909int event_cli_write(int fd);
910int event_srv_read(int fd);
911int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100912int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100913
willy tarreau12350152005-12-18 01:03:27 +0100914static int appsession_task_init(void);
915static int appsession_init(void);
916static int appsession_refresh(struct task *t);
917
willy tarreau0f7af912005-12-17 12:21:26 +0100918/*********************************************************************/
919/* general purpose functions ***************************************/
920/*********************************************************************/
921
922void display_version() {
923 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100924 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100925}
926
927/*
928 * This function prints the command line usage and exits
929 */
930void usage(char *name) {
931 display_version();
932 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100933 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100934#if STATTIME > 0
935 "sl"
936#endif
willy tarreau746e26b2006-03-25 11:14:35 +0100937 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
938 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100939 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100940 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +0100941 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100942#if STATTIME > 0
943 " -s enables statistics output\n"
944 " -l enables long statistics format\n"
945#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100946 " -D goes daemon ; implies -q\n"
947 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100948 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100949 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +0100950 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100951 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100952 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100953#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100954 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100955#endif
956#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100957 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100958#endif
willy tarreau53e99702006-03-25 18:53:50 +0100959 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100960 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100961 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100962 exit(1);
963}
964
965
966/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100967 * Displays the message on stderr with the date and pid. Overrides the quiet
968 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100969 */
970void Alert(char *fmt, ...) {
971 va_list argp;
972 struct timeval tv;
973 struct tm *tm;
974
willy tarreaud0fb4652005-12-18 01:32:04 +0100975 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100976 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100977
willy tarreau5cbea6f2005-12-17 12:48:26 +0100978 gettimeofday(&tv, NULL);
979 tm=localtime(&tv.tv_sec);
980 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100981 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100982 vfprintf(stderr, fmt, argp);
983 fflush(stderr);
984 va_end(argp);
985 }
willy tarreau0f7af912005-12-17 12:21:26 +0100986}
987
988
989/*
990 * Displays the message on stderr with the date and pid.
991 */
992void Warning(char *fmt, ...) {
993 va_list argp;
994 struct timeval tv;
995 struct tm *tm;
996
willy tarreau982249e2005-12-18 00:57:06 +0100997 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100998 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100999
willy tarreau5cbea6f2005-12-17 12:48:26 +01001000 gettimeofday(&tv, NULL);
1001 tm=localtime(&tv.tv_sec);
1002 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001003 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001004 vfprintf(stderr, fmt, argp);
1005 fflush(stderr);
1006 va_end(argp);
1007 }
1008}
1009
1010/*
1011 * Displays the message on <out> only if quiet mode is not set.
1012 */
1013void qfprintf(FILE *out, char *fmt, ...) {
1014 va_list argp;
1015
willy tarreau982249e2005-12-18 00:57:06 +01001016 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001017 va_start(argp, fmt);
1018 vfprintf(out, fmt, argp);
1019 fflush(out);
1020 va_end(argp);
1021 }
willy tarreau0f7af912005-12-17 12:21:26 +01001022}
1023
1024
1025/*
1026 * converts <str> to a struct sockaddr_in* which is locally allocated.
1027 * The format is "addr:port", where "addr" can be empty or "*" to indicate
1028 * INADDR_ANY.
1029 */
1030struct sockaddr_in *str2sa(char *str) {
1031 static struct sockaddr_in sa;
1032 char *c;
1033 int port;
1034
willy tarreaua1598082005-12-17 13:08:06 +01001035 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +01001036 str=strdup(str);
1037
1038 if ((c=strrchr(str,':')) != NULL) {
1039 *c++=0;
1040 port=atol(c);
1041 }
1042 else
1043 port=0;
1044
1045 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1046 sa.sin_addr.s_addr = INADDR_ANY;
1047 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01001048 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001049 struct hostent *he;
1050
1051 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001052 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001053 }
1054 else
1055 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1056 }
1057 sa.sin_port=htons(port);
1058 sa.sin_family=AF_INET;
1059
1060 free(str);
1061 return &sa;
1062}
1063
willy tarreaub1285d52005-12-18 01:20:14 +01001064/*
1065 * converts <str> to a two struct in_addr* which are locally allocated.
1066 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1067 * is optionnal and either in the dotted or CIDR notation.
1068 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1069 */
1070int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1071 char *c;
1072 unsigned long len;
1073
1074 memset(mask, 0, sizeof(*mask));
1075 memset(addr, 0, sizeof(*addr));
1076 str=strdup(str);
1077
1078 if ((c = strrchr(str, '/')) != NULL) {
1079 *c++ = 0;
1080 /* c points to the mask */
1081 if (strchr(c, '.') != NULL) { /* dotted notation */
1082 if (!inet_pton(AF_INET, c, mask))
1083 return 0;
1084 }
1085 else { /* mask length */
1086 char *err;
1087 len = strtol(c, &err, 10);
1088 if (!*c || (err && *err) || (unsigned)len > 32)
1089 return 0;
1090 if (len)
1091 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1092 else
1093 mask->s_addr = 0;
1094 }
1095 }
1096 else {
1097 mask->s_addr = 0xFFFFFFFF;
1098 }
1099 if (!inet_pton(AF_INET, str, addr)) {
1100 struct hostent *he;
1101
1102 if ((he = gethostbyname(str)) == NULL) {
1103 return 0;
1104 }
1105 else
1106 *addr = *(struct in_addr *) *(he->h_addr_list);
1107 }
1108 free(str);
1109 return 1;
1110}
1111
willy tarreau9fe663a2005-12-17 13:02:59 +01001112
1113/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001114 * converts <str> to a list of listeners which are dynamically allocated.
1115 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1116 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1117 * - <port> is a numerical port from 1 to 65535 ;
1118 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1119 * This can be repeated as many times as necessary, separated by a coma.
1120 * The <tail> argument is a pointer to a current list which should be appended
1121 * to the tail of the new list. The pointer to the new list is returned.
1122 */
1123struct listener *str2listener(char *str, struct listener *tail) {
1124 struct listener *l;
1125 char *c, *next, *range, *dupstr;
1126 int port, end;
1127
1128 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001129
willy tarreaua41a8b42005-12-17 14:02:24 +01001130 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001131 struct sockaddr_storage ss;
1132
willy tarreaua41a8b42005-12-17 14:02:24 +01001133 str = next;
1134 /* 1) look for the end of the first address */
1135 if ((next = strrchr(str, ',')) != NULL) {
1136 *next++ = 0;
1137 }
1138
willy tarreau8a86dbf2005-12-18 00:45:59 +01001139 /* 2) look for the addr/port delimiter, it's the last colon. */
1140 if ((range = strrchr(str, ':')) == NULL) {
1141 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001142 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001143 }
1144
1145 *range++ = 0;
1146
1147 if (strrchr(str, ':') != NULL) {
1148 /* IPv6 address contains ':' */
1149 memset(&ss, 0, sizeof(ss));
1150 ss.ss_family = AF_INET6;
1151
1152 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1153 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001154 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001155 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001156 }
1157 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001158 memset(&ss, 0, sizeof(ss));
1159 ss.ss_family = AF_INET;
1160
1161 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1162 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1163 }
1164 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1165 struct hostent *he;
1166
1167 if ((he = gethostbyname(str)) == NULL) {
1168 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001169 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001170 }
1171 else
1172 ((struct sockaddr_in *)&ss)->sin_addr =
1173 *(struct in_addr *) *(he->h_addr_list);
1174 }
1175 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001176
1177 /* 3) look for the port-end delimiter */
1178 if ((c = strchr(range, '-')) != NULL) {
1179 *c++ = 0;
1180 end = atol(c);
1181 }
1182 else {
1183 end = atol(range);
1184 }
1185
willy tarreaud0fb4652005-12-18 01:32:04 +01001186 port = atol(range);
1187
1188 if (port < 1 || port > 65535) {
1189 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1190 goto fail;
1191 }
1192
1193 if (end < 1 || end > 65535) {
1194 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1195 goto fail;
1196 }
1197
1198 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001199 l = (struct listener *)calloc(1, sizeof(struct listener));
1200 l->next = tail;
1201 tail = l;
1202
willy tarreau41310e72006-03-25 18:17:56 +01001203 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001204 l->addr = ss;
1205 if (ss.ss_family == AF_INET6)
1206 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1207 else
1208 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1209
willy tarreaua41a8b42005-12-17 14:02:24 +01001210 } /* end for(port) */
1211 } /* end while(next) */
1212 free(dupstr);
1213 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001214 fail:
1215 free(dupstr);
1216 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001217}
1218
willy tarreau4302f492005-12-18 01:00:37 +01001219
1220#define FD_SETS_ARE_BITFIELDS
1221#ifdef FD_SETS_ARE_BITFIELDS
1222/*
1223 * This map is used with all the FD_* macros to check whether a particular bit
1224 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1225 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1226 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1227 * exclusively to the macros.
1228 */
1229fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1230fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1231
1232#else
1233#error "Check if your OS uses bitfields for fd_sets"
1234#endif
1235
1236/* will try to encode the string <string> replacing all characters tagged in
1237 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1238 * prefixed by <escape>, and will store the result between <start> (included
1239 *) and <stop> (excluded), and will always terminate the string with a '\0'
1240 * before <stop>. The position of the '\0' is returned if the conversion
1241 * completes. If bytes are missing between <start> and <stop>, then the
1242 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1243 * cannot even be stored so we return <start> without writing the 0.
1244 * The input string must also be zero-terminated.
1245 */
1246char hextab[16] = "0123456789ABCDEF";
1247char *encode_string(char *start, char *stop,
1248 const char escape, const fd_set *map,
1249 const char *string)
1250{
1251 if (start < stop) {
1252 stop--; /* reserve one byte for the final '\0' */
1253 while (start < stop && *string != 0) {
1254 if (!FD_ISSET((unsigned char)(*string), map))
1255 *start++ = *string;
1256 else {
1257 if (start + 3 >= stop)
1258 break;
1259 *start++ = escape;
1260 *start++ = hextab[(*string >> 4) & 15];
1261 *start++ = hextab[*string & 15];
1262 }
1263 string++;
1264 }
1265 *start = '\0';
1266 }
1267 return start;
1268}
willy tarreaua41a8b42005-12-17 14:02:24 +01001269
1270/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001271 * This function sends a syslog message to both log servers of a proxy,
1272 * or to global log servers if the proxy is NULL.
1273 * It also tries not to waste too much time computing the message header.
1274 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001275 */
1276void send_log(struct proxy *p, int level, char *message, ...) {
1277 static int logfd = -1; /* syslog UDP socket */
1278 static long tvsec = -1; /* to force the string to be initialized */
1279 struct timeval tv;
1280 va_list argp;
1281 static char logmsg[MAX_SYSLOG_LEN];
1282 static char *dataptr = NULL;
1283 int fac_level;
1284 int hdr_len, data_len;
1285 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001286 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001287 int nbloggers = 0;
1288 char *log_ptr;
1289
1290 if (logfd < 0) {
1291 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1292 return;
1293 }
1294
1295 if (level < 0 || progname == NULL || message == NULL)
1296 return;
1297
1298 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001299 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001300 /* this string is rebuild only once a second */
1301 struct tm *tm = localtime(&tv.tv_sec);
1302 tvsec = tv.tv_sec;
1303
willy tarreauc29948c2005-12-17 13:10:27 +01001304 hdr_len = snprintf(logmsg, sizeof(logmsg),
1305 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1306 monthname[tm->tm_mon],
1307 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1308 progname, pid);
1309 /* WARNING: depending upon implementations, snprintf may return
1310 * either -1 or the number of bytes that would be needed to store
1311 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001312 */
willy tarreauc29948c2005-12-17 13:10:27 +01001313 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1314 hdr_len = sizeof(logmsg);
1315
1316 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001317 }
1318
1319 va_start(argp, message);
1320 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001321 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1322 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001323 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001324 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001325
1326 if (p == NULL) {
1327 if (global.logfac1 >= 0) {
1328 sa[nbloggers] = &global.logsrv1;
1329 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001330 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001331 nbloggers++;
1332 }
1333 if (global.logfac2 >= 0) {
1334 sa[nbloggers] = &global.logsrv2;
1335 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001336 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001337 nbloggers++;
1338 }
1339 } else {
1340 if (p->logfac1 >= 0) {
1341 sa[nbloggers] = &p->logsrv1;
1342 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001343 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001344 nbloggers++;
1345 }
1346 if (p->logfac2 >= 0) {
1347 sa[nbloggers] = &p->logsrv2;
1348 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001349 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001350 nbloggers++;
1351 }
1352 }
1353
1354 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001355 /* we can filter the level of the messages that are sent to each logger */
1356 if (level > loglevel[nbloggers])
1357 continue;
1358
willy tarreauc29948c2005-12-17 13:10:27 +01001359 /* For each target, we may have a different facility.
1360 * We can also have a different log level for each message.
1361 * This induces variations in the message header length.
1362 * Since we don't want to recompute it each time, nor copy it every
1363 * time, we only change the facility in the pre-computed header,
1364 * and we change the pointer to the header accordingly.
1365 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001366 fac_level = (facilities[nbloggers] << 3) + level;
1367 log_ptr = logmsg + 3; /* last digit of the log level */
1368 do {
1369 *log_ptr = '0' + fac_level % 10;
1370 fac_level /= 10;
1371 log_ptr--;
1372 } while (fac_level && log_ptr > logmsg);
1373 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001374
willy tarreauc29948c2005-12-17 13:10:27 +01001375 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001376
1377#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001378 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001379 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1380#else
willy tarreauc29948c2005-12-17 13:10:27 +01001381 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001382 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1383#endif
1384 }
willy tarreau0f7af912005-12-17 12:21:26 +01001385}
1386
1387
1388/* sets <tv> to the current time */
1389static inline struct timeval *tv_now(struct timeval *tv) {
1390 if (tv)
1391 gettimeofday(tv, NULL);
1392 return tv;
1393}
1394
1395/*
1396 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1397 */
willy tarreaudab722b2006-05-04 19:23:38 +02001398static struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
willy tarreau0f7af912005-12-17 12:21:26 +01001399 if (!tv || !from)
1400 return NULL;
1401 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1402 tv->tv_sec = from->tv_sec + (ms/1000);
1403 while (tv->tv_usec >= 1000000) {
1404 tv->tv_usec -= 1000000;
1405 tv->tv_sec++;
1406 }
1407 return tv;
1408}
1409
1410/*
1411 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001412 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001413 */
1414static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001415 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001416 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001417 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001418 return 1;
1419 else if (tv1->tv_usec < tv2->tv_usec)
1420 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001421 else if (tv1->tv_usec > tv2->tv_usec)
1422 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001423 else
1424 return 0;
1425}
1426
1427/*
1428 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001429 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001430 */
1431unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1432 int cmp;
1433 unsigned long ret;
1434
1435
willy tarreauef900ab2005-12-17 12:52:52 +01001436 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001437 if (!cmp)
1438 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001439 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001440 struct timeval *tmp = tv1;
1441 tv1 = tv2;
1442 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001443 }
willy tarreauef900ab2005-12-17 12:52:52 +01001444 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001445 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001446 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001447 else
willy tarreauef900ab2005-12-17 12:52:52 +01001448 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001449 return (unsigned long) ret;
1450}
1451
1452/*
willy tarreau750a4722005-12-17 13:21:24 +01001453 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001454 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001455 */
1456static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1457 unsigned long ret;
1458
willy tarreau6e682ce2005-12-17 13:26:49 +01001459 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1460 if (tv2->tv_usec > tv1->tv_usec)
1461 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001462 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001463 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001464 return (unsigned long) ret;
1465}
1466
1467/*
willy tarreau0f7af912005-12-17 12:21:26 +01001468 * 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 +01001469 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001470 */
willy tarreaudab722b2006-05-04 19:23:38 +02001471static int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001472 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001473 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001474 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001475 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001476 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001477 else
1478 return 0;
1479 }
willy tarreau0f7af912005-12-17 12:21:26 +01001480 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001481 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001482 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001483 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001484 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001485 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001486 else
1487 return 0;
1488}
1489
1490/*
1491 * returns the remaining time between tv1=now and event=tv2
1492 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001493 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001494 */
1495static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1496 unsigned long ret;
1497
willy tarreau0f7af912005-12-17 12:21:26 +01001498 if (tv_cmp_ms(tv1, tv2) >= 0)
1499 return 0; /* event elapsed */
1500
willy tarreauef900ab2005-12-17 12:52:52 +01001501 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001502 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001503 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001504 else
willy tarreauef900ab2005-12-17 12:52:52 +01001505 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001506 return (unsigned long) ret;
1507}
1508
1509
1510/*
1511 * zeroes a struct timeval
1512 */
1513
1514static inline struct timeval *tv_eternity(struct timeval *tv) {
1515 tv->tv_sec = tv->tv_usec = 0;
1516 return tv;
1517}
1518
1519/*
1520 * returns 1 if tv is null, else 0
1521 */
1522static inline int tv_iseternity(struct timeval *tv) {
1523 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1524 return 1;
1525 else
1526 return 0;
1527}
1528
1529/*
1530 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1531 * considering that 0 is the eternity.
1532 */
willy tarreaudab722b2006-05-04 19:23:38 +02001533static int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001534 if (tv_iseternity(tv1))
1535 if (tv_iseternity(tv2))
1536 return 0; /* same */
1537 else
1538 return 1; /* tv1 later than tv2 */
1539 else if (tv_iseternity(tv2))
1540 return -1; /* tv2 later than tv1 */
1541
1542 if (tv1->tv_sec > tv2->tv_sec)
1543 return 1;
1544 else if (tv1->tv_sec < tv2->tv_sec)
1545 return -1;
1546 else if (tv1->tv_usec > tv2->tv_usec)
1547 return 1;
1548 else if (tv1->tv_usec < tv2->tv_usec)
1549 return -1;
1550 else
1551 return 0;
1552}
1553
1554/*
1555 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1556 * considering that 0 is the eternity.
1557 */
willy tarreaudab722b2006-05-04 19:23:38 +02001558static int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001559 if (tv_iseternity(tv1))
1560 if (tv_iseternity(tv2))
1561 return 0; /* same */
1562 else
1563 return 1; /* tv1 later than tv2 */
1564 else if (tv_iseternity(tv2))
1565 return -1; /* tv2 later than tv1 */
1566
willy tarreauefae1842005-12-17 12:51:03 +01001567 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001568 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001569 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001570 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001571 return -1;
1572 else
1573 return 0;
1574 }
1575 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001576 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001577 return 1;
1578 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001579 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001580 return -1;
1581 else
1582 return 0;
1583}
1584
1585/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001586 * returns the remaining time between tv1=now and event=tv2
1587 * if tv2 is passed, 0 is returned.
1588 * Returns TIME_ETERNITY if tv2 is eternity.
1589 */
willy tarreaudab722b2006-05-04 19:23:38 +02001590static unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001591 unsigned long ret;
1592
1593 if (tv_iseternity(tv2))
1594 return TIME_ETERNITY;
1595
1596 if (tv_cmp_ms(tv1, tv2) >= 0)
1597 return 0; /* event elapsed */
1598
1599 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1600 if (tv2->tv_usec > tv1->tv_usec)
1601 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1602 else
1603 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1604 return (unsigned long) ret;
1605}
1606
1607/*
willy tarreau0f7af912005-12-17 12:21:26 +01001608 * returns the first event between tv1 and tv2 into tvmin.
1609 * a zero tv is ignored. tvmin is returned.
1610 */
1611static inline struct timeval *tv_min(struct timeval *tvmin,
1612 struct timeval *tv1, struct timeval *tv2) {
1613
1614 if (tv_cmp2(tv1, tv2) <= 0)
1615 *tvmin = *tv1;
1616 else
1617 *tvmin = *tv2;
1618
1619 return tvmin;
1620}
1621
1622
1623
1624/***********************************************************/
1625/* fd management ***************************************/
1626/***********************************************************/
1627
1628
1629
willy tarreau5cbea6f2005-12-17 12:48:26 +01001630/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1631 * The file descriptor is also closed.
1632 */
willy tarreaudab722b2006-05-04 19:23:38 +02001633static void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001634 FD_CLR(fd, StaticReadEvent);
1635 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001636#if defined(ENABLE_EPOLL)
1637 if (PrevReadEvent) {
1638 FD_CLR(fd, PrevReadEvent);
1639 FD_CLR(fd, PrevWriteEvent);
1640 }
1641#endif
1642
willy tarreau5cbea6f2005-12-17 12:48:26 +01001643 close(fd);
1644 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001645
1646 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1647 maxfd--;
1648}
1649
1650/* recomputes the maxfd limit from the fd */
1651static inline void fd_insert(int fd) {
1652 if (fd+1 > maxfd)
1653 maxfd = fd+1;
1654}
1655
1656/*************************************************************/
1657/* task management ***************************************/
1658/*************************************************************/
1659
willy tarreau5cbea6f2005-12-17 12:48:26 +01001660/* puts the task <t> in run queue <q>, and returns <t> */
1661static inline struct task *task_wakeup(struct task **q, struct task *t) {
1662 if (t->state == TASK_RUNNING)
1663 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001664 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001665 t->rqnext = *q;
1666 t->state = TASK_RUNNING;
1667 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001668 }
1669}
1670
willy tarreau5cbea6f2005-12-17 12:48:26 +01001671/* removes the task <t> from the queue <q>
1672 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001673 * set the run queue to point to the next one, and return it
1674 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001675static inline struct task *task_sleep(struct task **q, struct task *t) {
1676 if (t->state == TASK_RUNNING) {
1677 *q = t->rqnext;
1678 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001679 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001680 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001681}
1682
1683/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001684 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001685 * from the run queue. A pointer to the task itself is returned.
1686 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001687static inline struct task *task_delete(struct task *t) {
1688 t->prev->next = t->next;
1689 t->next->prev = t->prev;
1690 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001691}
1692
1693/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001694 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001695 */
1696static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001697 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001698}
1699
willy tarreau5cbea6f2005-12-17 12:48:26 +01001700/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001701 * may be only moved or left where it was, depending on its timing requirements.
1702 * <task> is returned.
1703 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001704struct task *task_queue(struct task *task) {
1705 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001706 struct task *start_from;
1707
willy tarreau5e698ef2006-05-02 14:51:00 +02001708 /* This is a very dirty hack to queue non-expirable tasks in another queue
1709 * in order to avoid pulluting the tail of the standard queue. This will go
1710 * away with the new O(log(n)) scheduler anyway.
1711 */
1712 if (tv_iseternity(&task->expire)) {
1713 /* if the task was queued in the standard wait queue, we must dequeue it */
1714 if (task->prev) {
1715 if (task->wq == LIST_HEAD(wait_queue[1]))
1716 return task;
1717 else {
1718 task_delete(task);
1719 task->prev = NULL;
1720 }
1721 }
1722 list = task->wq = LIST_HEAD(wait_queue[1]);
1723 } else {
1724 /* if the task was queued in the eternity queue, we must dequeue it */
1725 if (task->prev && (task->wq == LIST_HEAD(wait_queue[1]))) {
1726 task_delete(task);
1727 task->prev = NULL;
1728 list = task->wq = LIST_HEAD(wait_queue[0]);
1729 }
1730 }
1731
1732 /* next, test if the task was already in a list */
willy tarreau0f7af912005-12-17 12:21:26 +01001733 if (task->prev == NULL) {
1734 // start_from = list;
1735 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001736#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001737 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001738#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001739 /* insert the unlinked <task> into the list, searching back from the last entry */
1740 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1741 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001742#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001743 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001744#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001745 }
1746
1747 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1748 // start_from = start_from->next;
1749 // stats_tsk_nsrch++;
1750 // }
1751 }
1752 else if (task->prev == list ||
1753 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1754 start_from = task->next;
1755 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001756#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001757 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001758#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001759 return task; /* it's already in the right place */
1760 }
1761
willy tarreau750a4722005-12-17 13:21:24 +01001762#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001763 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001764#endif
1765
1766 /* if the task is not at the right place, there's little chance that
1767 * it has only shifted a bit, and it will nearly always be queued
1768 * at the end of the list because of constant timeouts
1769 * (observed in real case).
1770 */
1771#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1772 start_from = list->prev; /* assume we'll queue to the end of the list */
1773 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1774 start_from = start_from->prev;
1775#if STATTIME > 0
1776 stats_tsk_lsrch++;
1777#endif
1778 }
1779#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001780 /* insert the unlinked <task> into the list, searching after position <start_from> */
1781 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1782 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001783#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001784 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001785#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001786 }
willy tarreau750a4722005-12-17 13:21:24 +01001787#endif /* WE_REALLY_... */
1788
willy tarreau0f7af912005-12-17 12:21:26 +01001789 /* we need to unlink it now */
1790 task_delete(task);
1791 }
1792 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001793#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001794 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001795#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001796#ifdef LEFT_TO_TOP /* not very good */
1797 start_from = list;
1798 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1799 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001800#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001801 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001802#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001803 }
1804#else
1805 start_from = task->prev->prev; /* valid because of the previous test above */
1806 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1807 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001808#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001809 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001810#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001811 }
1812#endif
1813 /* we need to unlink it now */
1814 task_delete(task);
1815 }
1816 task->prev = start_from;
1817 task->next = start_from->next;
1818 task->next->prev = task;
1819 start_from->next = task;
1820 return task;
1821}
1822
1823
1824/*********************************************************************/
willy tarreau18a957c2006-04-12 19:26:23 +02001825/* pending connections queues **************************************/
1826/*********************************************************************/
1827
1828/*
willy tarreaudfece232006-05-02 00:19:57 +02001829 * Detaches pending connection <p>, decreases the pending count, and frees
1830 * the pending connection. The connection might have been queued to a specific
1831 * server as well as to the proxy. The session also gets marked unqueued.
willy tarreau18a957c2006-04-12 19:26:23 +02001832 */
willy tarreaudfece232006-05-02 00:19:57 +02001833static void pendconn_free(struct pendconn *p) {
1834 LIST_DEL(&p->list);
1835 p->sess->pend_pos = NULL;
1836 if (p->srv)
1837 p->srv->nbpend--;
1838 else
1839 p->sess->proxy->nbpend--;
willy tarreauf32f5242006-05-02 22:54:52 +02001840 p->sess->proxy->totpend--;
willy tarreaudfece232006-05-02 00:19:57 +02001841 pool_free(pendconn, p);
1842}
1843
1844/* Returns the first pending connection for server <s>, which may be NULL if
1845 * nothing is pending.
1846 */
1847static inline struct pendconn *pendconn_from_srv(struct server *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001848 if (!s->nbpend)
1849 return NULL;
1850
1851 return LIST_ELEM(s->pendconns.n, struct pendconn *, list);
1852}
1853
willy tarreaudfece232006-05-02 00:19:57 +02001854/* Returns the first pending connection for proxy <px>, which may be NULL if
1855 * nothing is pending.
willy tarreau18a957c2006-04-12 19:26:23 +02001856 */
willy tarreaudfece232006-05-02 00:19:57 +02001857static inline struct pendconn *pendconn_from_px(struct proxy *px) {
1858 if (!px->nbpend)
1859 return NULL;
1860
1861 return LIST_ELEM(px->pendconns.n, struct pendconn *, list);
willy tarreau18a957c2006-04-12 19:26:23 +02001862}
1863
willy tarreaubc2eda62006-05-04 15:16:23 +02001864/* Detaches the next pending connection from either a server or a proxy, and
1865 * returns its associated session. If no pending connection is found, NULL is
1866 * returned. Note that neither <srv> nor <px> can be NULL.
willy tarreau18a957c2006-04-12 19:26:23 +02001867 */
willy tarreaubc2eda62006-05-04 15:16:23 +02001868static struct session *pendconn_get_next_sess(struct server *srv, struct proxy *px) {
willy tarreau18a957c2006-04-12 19:26:23 +02001869 struct pendconn *p;
1870 struct session *sess;
1871
willy tarreaubc2eda62006-05-04 15:16:23 +02001872 p = pendconn_from_srv(srv);
willy tarreaudfece232006-05-02 00:19:57 +02001873 if (!p) {
willy tarreaubc2eda62006-05-04 15:16:23 +02001874 p = pendconn_from_px(px);
willy tarreaudfece232006-05-02 00:19:57 +02001875 if (!p)
1876 return NULL;
willy tarreaubc2eda62006-05-04 15:16:23 +02001877 p->sess->srv = srv;
willy tarreaudfece232006-05-02 00:19:57 +02001878 }
willy tarreau18a957c2006-04-12 19:26:23 +02001879 sess = p->sess;
1880 pendconn_free(p);
1881 return sess;
1882}
1883
willy tarreaudfece232006-05-02 00:19:57 +02001884/* Adds the session <sess> to the pending connection list of server <sess>->srv
1885 * or to the one of <sess>->proxy if srv is NULL. All counters and back pointers
1886 * are updated accordingly. Returns NULL if no memory is available, otherwise the
1887 * pendconn itself.
willy tarreau18a957c2006-04-12 19:26:23 +02001888 */
willy tarreaudfece232006-05-02 00:19:57 +02001889static struct pendconn *pendconn_add(struct session *sess) {
willy tarreau18a957c2006-04-12 19:26:23 +02001890 struct pendconn *p;
1891
1892 p = pool_alloc(pendconn);
1893 if (!p)
1894 return NULL;
1895
willy tarreau18a957c2006-04-12 19:26:23 +02001896 sess->pend_pos = p;
willy tarreaudfece232006-05-02 00:19:57 +02001897 p->sess = sess;
1898 p->srv = sess->srv;
1899 if (sess->srv) {
1900 LIST_ADDQ(&sess->srv->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001901 sess->logs.srv_queue_size += sess->srv->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001902 sess->srv->nbpend++;
1903 } else {
1904 LIST_ADDQ(&sess->proxy->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001905 sess->logs.prx_queue_size += sess->proxy->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001906 sess->proxy->nbpend++;
1907 }
willy tarreauf32f5242006-05-02 22:54:52 +02001908 sess->proxy->totpend++;
willy tarreau18a957c2006-04-12 19:26:23 +02001909 return p;
1910}
1911
willy tarreau59a6cc22006-05-12 01:29:08 +02001912/* returns 0 if nothing has to be done for server <s> regarding queued connections,
1913 * and non-zero otherwise. Suited for and if/else usage.
1914 */
1915static inline int may_dequeue_tasks(struct server *s, struct proxy *p) {
1916 return (s && (s->nbpend || p->nbpend) &&
1917 s->maxconn && s->cur_sess < s->maxconn && s->queue_mgt);
1918}
1919
1920
1921
willy tarreau18a957c2006-04-12 19:26:23 +02001922/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +01001923/* more specific functions ***************************************/
1924/*********************************************************************/
1925
1926/* some prototypes */
1927static int maintain_proxies(void);
1928
willy tarreaub952e1d2005-12-18 01:31:20 +01001929/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001930 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1931 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001932static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001933#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001934 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1935#else
willy tarreaua1598082005-12-17 13:08:06 +01001936#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001937 return getsockname(fd, (struct sockaddr *)sa, salen);
1938#else
1939 return -1;
1940#endif
1941#endif
1942}
1943
1944/*
1945 * frees the context associated to a session. It must have been removed first.
1946 */
willy tarreaudfece232006-05-02 00:19:57 +02001947static void session_free(struct session *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001948 if (s->pend_pos)
1949 pendconn_free(s->pend_pos);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001950 if (s->req)
1951 pool_free(buffer, s->req);
1952 if (s->rep)
1953 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001954
1955 if (s->rsp_cap != NULL) {
1956 struct cap_hdr *h;
1957 for (h = s->proxy->rsp_cap; h; h = h->next) {
1958 if (s->rsp_cap[h->index] != NULL)
1959 pool_free_to(h->pool, s->rsp_cap[h->index]);
1960 }
1961 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1962 }
1963 if (s->req_cap != NULL) {
1964 struct cap_hdr *h;
1965 for (h = s->proxy->req_cap; h; h = h->next) {
1966 if (s->req_cap[h->index] != NULL)
1967 pool_free_to(h->pool, s->req_cap[h->index]);
1968 }
1969 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1970 }
1971
willy tarreaua1598082005-12-17 13:08:06 +01001972 if (s->logs.uri)
1973 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001974 if (s->logs.cli_cookie)
1975 pool_free(capture, s->logs.cli_cookie);
1976 if (s->logs.srv_cookie)
1977 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001978
willy tarreau5cbea6f2005-12-17 12:48:26 +01001979 pool_free(session, s);
1980}
1981
willy tarreau0f7af912005-12-17 12:21:26 +01001982
1983/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01001984 * This function recounts the number of usable active and backup servers for
1985 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001986 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01001987 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001988static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001989 struct server *srv;
1990
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001991 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001992 for (srv = px->srv; srv != NULL; srv = srv->next) {
1993 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001994 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001995 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001996 px->tot_wbck += srv->eweight + 1;
1997 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001998 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001999 px->tot_wact += srv->eweight + 1;
2000 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01002001 }
2002 }
2003}
2004
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002005/* This function recomputes the server map for proxy px. It
2006 * relies on px->tot_wact and px->tot_wbck, so it must be
2007 * called after recount_servers(). It also expects px->srv_map
2008 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01002009 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002010static void recalc_server_map(struct proxy *px) {
2011 int o, tot, flag;
2012 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01002013
willy tarreau4c8c2b52006-03-24 19:36:41 +01002014 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002015 flag = SRV_RUNNING;
2016 tot = px->tot_wact;
2017 } else if (px->srv_bck) {
2018 flag = SRV_RUNNING | SRV_BACKUP;
2019 if (px->options & PR_O_USE_ALL_BK)
2020 tot = px->tot_wbck;
2021 else
2022 tot = 1; /* the first server is enough */
2023 } else {
2024 px->srv_map_sz = 0;
2025 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002026 }
Willy TARREAU3481c462006-03-01 22:37:57 +01002027
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002028 /* this algorithm gives priority to the first server, which means that
2029 * it will respect the declaration order for equivalent weights, and
2030 * that whatever the weights, the first server called will always be
2031 * the first declard. This is an important asumption for the backup
2032 * case, where we want the first server only.
2033 */
2034 for (cur = px->srv; cur; cur = cur->next)
2035 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002036
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002037 for (o = 0; o < tot; o++) {
2038 int max = 0;
2039 best = NULL;
2040 for (cur = px->srv; cur; cur = cur->next) {
2041 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
2042 int v;
2043
2044 /* If we are forced to return only one server, we don't want to
2045 * go further, because we would return the wrong one due to
2046 * divide overflow.
2047 */
2048 if (tot == 1) {
2049 best = cur;
2050 break;
2051 }
2052
2053 cur->wscore += cur->eweight + 1;
2054 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
2055 if (best == NULL || v > max) {
2056 max = v;
2057 best = cur;
2058 }
2059 }
2060 }
2061 px->srv_map[o] = best;
2062 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002063 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002064 px->srv_map_sz = tot;
2065}
Willy TARREAU3481c462006-03-01 22:37:57 +01002066
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002067/*
willy tarreau898db9d2006-04-12 20:29:08 +02002068 * This function tries to find a running server with free connection slots for
2069 * the proxy <px> following the round-robin method.
2070 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2071 * to point to the next server. If no valid server is found, NULL is returned.
2072 */
2073static inline struct server *get_server_rr_with_conns(struct proxy *px) {
2074 int newidx;
2075 struct server *srv;
2076
2077 if (px->srv_map_sz == 0)
2078 return NULL;
2079
2080 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2081 px->srv_rr_idx = 0;
2082 newidx = px->srv_rr_idx;
2083
2084 do {
2085 srv = px->srv_map[newidx++];
2086 if (!srv->maxconn || srv->cur_sess < srv->maxconn) {
2087 px->srv_rr_idx = newidx;
2088 return srv;
2089 }
2090 if (newidx == px->srv_map_sz)
2091 newidx = 0;
2092 } while (newidx != px->srv_rr_idx);
2093
2094 return NULL;
2095}
2096
2097
2098/*
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002099 * This function tries to find a running server for the proxy <px> following
willy tarreau898db9d2006-04-12 20:29:08 +02002100 * the round-robin method.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002101 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2102 * to point to the next server. If no valid server is found, NULL is returned.
2103 */
2104static inline struct server *get_server_rr(struct proxy *px) {
2105 if (px->srv_map_sz == 0)
2106 return NULL;
2107
2108 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2109 px->srv_rr_idx = 0;
2110 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01002111}
2112
willy tarreau62084d42006-03-24 18:57:41 +01002113
2114/*
willy tarreau1a3442d2006-03-24 21:03:20 +01002115 * This function tries to find a running server for the proxy <px> following
2116 * the source hash method. Depending on the number of active/backup servers,
2117 * it will either look for active servers, or for backup servers.
2118 * If any server is found, it will be returned. If no valid server is found,
2119 * NULL is returned.
2120 */
2121static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002122 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01002123
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002124 if (px->srv_map_sz == 0)
2125 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01002126
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002127 l = h = 0;
willy tarreaucd655352006-04-29 12:11:46 +02002128 if (px->srv_act > 1 || (px->srv_act == 0 && px->srv_bck > 1)) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002129 while ((l + sizeof (int)) <= len) {
2130 h ^= ntohl(*(unsigned int *)(&addr[l]));
2131 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01002132 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002133 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01002134 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002135 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01002136}
2137
2138
2139/*
willy tarreaudfece232006-05-02 00:19:57 +02002140 * This function marks the session as 'assigned' in direct or dispatch modes,
2141 * or tries to assign one in balance mode, according to the algorithm. It does
2142 * nothing if the session had already been assigned a server.
2143 *
2144 * It may return :
willy tarreau000375f2006-05-09 23:15:58 +02002145 * SRV_STATUS_OK if everything is OK. s->srv will be valid.
2146 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
2147 * SRV_STATUS_FULL if all servers are saturated. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002148 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2149 *
2150 * Upon successful return, the session flag SN_ASSIGNED to indicate that it does
2151 * not need to be called anymore. This usually means that s->srv can be trusted
2152 * in balance and direct modes. This flag is not cleared, so it's to the caller
2153 * to clear it if required (eg: redispatch).
2154 *
willy tarreau0f7af912005-12-17 12:21:26 +01002155 */
willy tarreau0f7af912005-12-17 12:21:26 +01002156
willy tarreaudfece232006-05-02 00:19:57 +02002157int assign_server(struct session *s) {
willy tarreau12350152005-12-18 01:03:27 +01002158#ifdef DEBUG_FULL
willy tarreaudfece232006-05-02 00:19:57 +02002159 fprintf(stderr,"assign_server : s=%p\n",s);
willy tarreau12350152005-12-18 01:03:27 +01002160#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002161
willy tarreaudfece232006-05-02 00:19:57 +02002162 if (s->pend_pos)
2163 return SRV_STATUS_INTERNAL;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002164
willy tarreaudfece232006-05-02 00:19:57 +02002165 if (!(s->flags & SN_ASSIGNED)) {
2166 if ((s->proxy->options & PR_O_BALANCE) && !(s->flags & SN_DIRECT)) {
2167 if (!s->proxy->srv_act && !s->proxy->srv_bck)
2168 return SRV_STATUS_NOSRV;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002169
willy tarreaudfece232006-05-02 00:19:57 +02002170 if (s->proxy->options & PR_O_BALANCE_RR) {
2171 s->srv = get_server_rr_with_conns(s->proxy);
2172 if (!s->srv)
2173 return SRV_STATUS_FULL;
2174 }
2175 else if (s->proxy->options & PR_O_BALANCE_SH) {
2176 int len;
2177
2178 if (s->cli_addr.ss_family == AF_INET)
2179 len = 4;
2180 else if (s->cli_addr.ss_family == AF_INET6)
2181 len = 16;
2182 else /* unknown IP family */
2183 return SRV_STATUS_INTERNAL;
2184
2185 s->srv = get_server_sh(s->proxy,
2186 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2187 len);
2188 }
2189 else /* unknown balancing algorithm */
2190 return SRV_STATUS_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002191 }
willy tarreaudfece232006-05-02 00:19:57 +02002192 s->flags |= SN_ASSIGNED;
2193 }
2194 return SRV_STATUS_OK;
2195}
willy tarreau1a3442d2006-03-24 21:03:20 +01002196
willy tarreaudfece232006-05-02 00:19:57 +02002197/*
2198 * This function assigns a server address to a session, and sets SN_ADDR_SET.
2199 * The address is taken from the currently assigned server, or from the
2200 * dispatch or transparent address.
2201 *
2202 * It may return :
2203 * SRV_STATUS_OK if everything is OK.
2204 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2205 *
2206 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
2207 * not cleared, so it's to the caller to clear it if required.
2208 *
2209 */
2210int assign_server_address(struct session *s) {
2211#ifdef DEBUG_FULL
2212 fprintf(stderr,"assign_server_address : s=%p\n",s);
2213#endif
2214
2215 if (s->flags & SN_DIRECT || s->proxy->options & PR_O_BALANCE) {
2216 /* A server is necessarily known for this session */
2217 if (!(s->flags & SN_ASSIGNED))
2218 return SRV_STATUS_INTERNAL;
2219
2220 s->srv_addr = s->srv->addr;
willy tarreau1a3442d2006-03-24 21:03:20 +01002221
willy tarreaudfece232006-05-02 00:19:57 +02002222 /* if this server remaps proxied ports, we'll use
2223 * the port the client connected to with an offset. */
2224 if (s->srv->state & SRV_MAPPORTS) {
2225 struct sockaddr_in sockname;
2226 socklen_t namelen = sizeof(sockname);
2227
2228 if (!(s->proxy->options & PR_O_TRANSP) ||
2229 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2230 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2231 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
willy tarreau1a3442d2006-03-24 21:03:20 +01002232 }
willy tarreau0f7af912005-12-17 12:21:26 +01002233 }
willy tarreaua1598082005-12-17 13:08:06 +01002234 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002235 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002236 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002237 }
2238 else if (s->proxy->options & PR_O_TRANSP) {
2239 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002240 socklen_t salen = sizeof(s->srv_addr);
2241
willy tarreau5cbea6f2005-12-17 12:48:26 +01002242 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2243 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaudfece232006-05-02 00:19:57 +02002244 return SRV_STATUS_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002245 }
2246 }
willy tarreau0f7af912005-12-17 12:21:26 +01002247
willy tarreaudfece232006-05-02 00:19:57 +02002248 s->flags |= SN_ADDR_SET;
2249 return SRV_STATUS_OK;
2250}
willy tarreaua41a8b42005-12-17 14:02:24 +01002251
willy tarreaudfece232006-05-02 00:19:57 +02002252/* This function assigns a server to session <s> if required, and can add the
2253 * connection to either the assigned server's queue or to the proxy's queue.
2254 *
2255 * Returns :
2256 *
2257 * SRV_STATUS_OK if everything is OK.
willy tarreau000375f2006-05-09 23:15:58 +02002258 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002259 * SRV_STATUS_QUEUED if the connection has been queued.
2260 * SRV_STATUS_FULL if the server(s) is/are saturated and the
2261 * connection could not be queued.
2262 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2263 *
2264 */
2265int assign_server_and_queue(struct session *s) {
2266 struct pendconn *p;
2267 int err;
2268
2269 if (s->pend_pos)
2270 return SRV_STATUS_INTERNAL;
2271
2272 if (s->flags & SN_ASSIGNED) {
2273 /* a server does not need to be assigned, perhaps because we're in
2274 * direct mode, or in dispatch or transparent modes where the server
2275 * is not needed.
2276 */
2277 if (s->srv &&
2278 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2279 p = pendconn_add(s);
2280 if (p)
2281 return SRV_STATUS_QUEUED;
2282 else
2283 return SRV_STATUS_FULL;
2284 }
2285 return SRV_STATUS_OK;
2286 }
2287
2288 /* a server needs to be assigned */
2289 err = assign_server(s);
2290 switch (err) {
2291 case SRV_STATUS_OK:
2292 /* in balance mode, we might have servers with connection limits */
2293 if (s->srv != NULL &&
2294 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2295 p = pendconn_add(s);
2296 if (p)
2297 return SRV_STATUS_QUEUED;
2298 else
2299 return SRV_STATUS_FULL;
2300 }
2301 return SRV_STATUS_OK;
2302
2303 case SRV_STATUS_FULL:
2304 /* queue this session into the proxy's queue */
2305 p = pendconn_add(s);
2306 if (p)
2307 return SRV_STATUS_QUEUED;
2308 else
2309 return SRV_STATUS_FULL;
2310
2311 case SRV_STATUS_NOSRV:
2312 case SRV_STATUS_INTERNAL:
2313 return err;
2314 default:
2315 return SRV_STATUS_INTERNAL;
willy tarreaua41a8b42005-12-17 14:02:24 +01002316 }
willy tarreaudfece232006-05-02 00:19:57 +02002317}
2318
2319
2320/*
2321 * This function initiates a connection to the server assigned to this session
2322 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
2323 * It can return one of :
2324 * - SN_ERR_NONE if everything's OK
2325 * - SN_ERR_SRVTO if there are no more servers
2326 * - SN_ERR_SRVCL if the connection was refused by the server
2327 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
2328 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
2329 * - SN_ERR_INTERNAL for any other purely internal errors
2330 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
2331 */
2332int connect_server(struct session *s) {
2333 int fd, err;
2334
2335 if (!(s->flags & SN_ADDR_SET)) {
2336 err = assign_server_address(s);
2337 if (err != SRV_STATUS_OK)
2338 return SN_ERR_INTERNAL;
2339 }
willy tarreaua41a8b42005-12-17 14:02:24 +01002340
willy tarreau0f7af912005-12-17 12:21:26 +01002341 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002342 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002343
2344 if (errno == ENFILE)
2345 send_log(s->proxy, LOG_EMERG,
2346 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2347 s->proxy->id, maxfd);
2348 else if (errno == EMFILE)
2349 send_log(s->proxy, LOG_EMERG,
2350 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2351 s->proxy->id, maxfd);
2352 else if (errno == ENOBUFS || errno == ENOMEM)
2353 send_log(s->proxy, LOG_EMERG,
2354 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2355 s->proxy->id, maxfd);
2356 /* this is a resource error */
2357 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002358 }
2359
willy tarreau9fe663a2005-12-17 13:02:59 +01002360 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002361 /* do not log anything there, it's a normal condition when this option
2362 * is used to serialize connections to a server !
2363 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002364 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2365 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002366 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002367 }
2368
willy tarreau0f7af912005-12-17 12:21:26 +01002369 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2370 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002371 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002372 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002373 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002374 }
2375
willy tarreaub952e1d2005-12-18 01:31:20 +01002376 if (s->proxy->options & PR_O_TCP_SRV_KA)
2377 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2378
willy tarreau0174f312005-12-18 01:02:42 +01002379 /* allow specific binding :
2380 * - server-specific at first
2381 * - proxy-specific next
2382 */
2383 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2384 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2385 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2386 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2387 s->proxy->id, s->srv->id);
2388 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002389 send_log(s->proxy, LOG_EMERG,
2390 "Cannot bind to source address before connect() for server %s/%s.\n",
2391 s->proxy->id, s->srv->id);
2392 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002393 }
2394 }
2395 else if (s->proxy->options & PR_O_BIND_SRC) {
2396 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2397 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2398 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2399 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002400 send_log(s->proxy, LOG_EMERG,
2401 "Cannot bind to source address before connect() for server %s/%s.\n",
2402 s->proxy->id, s->srv->id);
2403 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002404 }
willy tarreaua1598082005-12-17 13:08:06 +01002405 }
2406
willy tarreaub1285d52005-12-18 01:20:14 +01002407 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2408 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2409
2410 if (errno == EAGAIN || errno == EADDRINUSE) {
2411 char *msg;
2412 if (errno == EAGAIN) /* no free ports left, try again later */
2413 msg = "no free ports";
2414 else
2415 msg = "local address already in use";
2416
2417 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002418 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002419 send_log(s->proxy, LOG_EMERG,
2420 "Connect() failed for server %s/%s: %s.\n",
2421 s->proxy->id, s->srv->id, msg);
2422 return SN_ERR_RESOURCE;
2423 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002424 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002425 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002426 return SN_ERR_SRVTO;
2427 } else {
2428 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002429 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002430 close(fd);
2431 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002432 }
2433 }
2434
willy tarreau5cbea6f2005-12-17 12:48:26 +01002435 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002436 fdtab[fd].read = &event_srv_read;
2437 fdtab[fd].write = &event_srv_write;
2438 fdtab[fd].state = FD_STCONN; /* connection in progress */
2439
2440 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002441#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2442 if (PrevReadEvent) {
2443 assert(!(FD_ISSET(fd, PrevReadEvent)));
2444 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2445 }
2446#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002447
2448 fd_insert(fd);
willy tarreau926a3572006-05-01 15:26:35 +02002449 if (s->srv)
2450 s->srv->cur_sess++;
willy tarreau0f7af912005-12-17 12:21:26 +01002451
2452 if (s->proxy->contimeout)
2453 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2454 else
2455 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002456 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002457}
2458
2459/*
2460 * this function is called on a read event from a client socket.
2461 * It returns 0.
2462 */
2463int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002464 struct task *t = fdtab[fd].owner;
2465 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002466 struct buffer *b = s->req;
2467 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002468
willy tarreau12350152005-12-18 01:03:27 +01002469#ifdef DEBUG_FULL
2470 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2471#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002472
willy tarreau0f7af912005-12-17 12:21:26 +01002473 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002474#ifdef FILL_BUFFERS
2475 while (1)
2476#else
2477 do
2478#endif
2479 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002480 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2481 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002482 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002483 }
2484 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002485 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002486 }
2487 else {
2488 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002489 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2490 * since it means that the rewrite protection has been removed. This
2491 * implies that the if statement can be removed.
2492 */
2493 if (max > b->rlim - b->data)
2494 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002495 }
2496
2497 if (max == 0) { /* not anymore room to store data */
2498 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002499 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002500 }
2501
willy tarreau3242e862005-12-17 12:27:53 +01002502#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002503 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002504 int skerr;
2505 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002506
willy tarreau5cbea6f2005-12-17 12:48:26 +01002507 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2508 if (skerr)
2509 ret = -1;
2510 else
2511 ret = recv(fd, b->r, max, 0);
2512 }
willy tarreau3242e862005-12-17 12:27:53 +01002513#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002514 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002515#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002516 if (ret > 0) {
2517 b->r += ret;
2518 b->l += ret;
2519 s->res_cr = RES_DATA;
2520
2521 if (b->r == b->data + BUFSIZE) {
2522 b->r = b->data; /* wrap around the buffer */
2523 }
willy tarreaua1598082005-12-17 13:08:06 +01002524
2525 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002526 /* we hope to read more data or to get a close on next round */
2527 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002528 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002529 else if (ret == 0) {
2530 s->res_cr = RES_NULL;
2531 break;
2532 }
2533 else if (errno == EAGAIN) {/* ignore EAGAIN */
2534 break;
2535 }
2536 else {
2537 s->res_cr = RES_ERROR;
2538 fdtab[fd].state = FD_STERROR;
2539 break;
2540 }
2541 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002542#ifndef FILL_BUFFERS
2543 while (0);
2544#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002545 }
2546 else {
2547 s->res_cr = RES_ERROR;
2548 fdtab[fd].state = FD_STERROR;
2549 }
2550
willy tarreau5cbea6f2005-12-17 12:48:26 +01002551 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002552 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002553 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2554 else
2555 tv_eternity(&s->crexpire);
2556
2557 task_wakeup(&rq, t);
2558 }
willy tarreau0f7af912005-12-17 12:21:26 +01002559
willy tarreau0f7af912005-12-17 12:21:26 +01002560 return 0;
2561}
2562
2563
2564/*
2565 * this function is called on a read event from a server socket.
2566 * It returns 0.
2567 */
2568int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002569 struct task *t = fdtab[fd].owner;
2570 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002571 struct buffer *b = s->rep;
2572 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002573
willy tarreau12350152005-12-18 01:03:27 +01002574#ifdef DEBUG_FULL
2575 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2576#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002577
willy tarreau0f7af912005-12-17 12:21:26 +01002578 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002579#ifdef FILL_BUFFERS
2580 while (1)
2581#else
2582 do
2583#endif
2584 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002585 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2586 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002587 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002588 }
2589 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002590 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002591 }
2592 else {
2593 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002594 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2595 * since it means that the rewrite protection has been removed. This
2596 * implies that the if statement can be removed.
2597 */
2598 if (max > b->rlim - b->data)
2599 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002600 }
2601
2602 if (max == 0) { /* not anymore room to store data */
2603 FD_CLR(fd, StaticReadEvent);
2604 break;
2605 }
2606
willy tarreau3242e862005-12-17 12:27:53 +01002607#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002608 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002609 int skerr;
2610 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002611
willy tarreau5cbea6f2005-12-17 12:48:26 +01002612 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2613 if (skerr)
2614 ret = -1;
2615 else
2616 ret = recv(fd, b->r, max, 0);
2617 }
willy tarreau3242e862005-12-17 12:27:53 +01002618#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002619 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002620#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002621 if (ret > 0) {
2622 b->r += ret;
2623 b->l += ret;
2624 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002625
willy tarreau5cbea6f2005-12-17 12:48:26 +01002626 if (b->r == b->data + BUFSIZE) {
2627 b->r = b->data; /* wrap around the buffer */
2628 }
willy tarreaua1598082005-12-17 13:08:06 +01002629
2630 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002631 /* we hope to read more data or to get a close on next round */
2632 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002633 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002634 else if (ret == 0) {
2635 s->res_sr = RES_NULL;
2636 break;
2637 }
2638 else if (errno == EAGAIN) {/* ignore EAGAIN */
2639 break;
2640 }
2641 else {
2642 s->res_sr = RES_ERROR;
2643 fdtab[fd].state = FD_STERROR;
2644 break;
2645 }
2646 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002647#ifndef FILL_BUFFERS
2648 while (0);
2649#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002650 }
2651 else {
2652 s->res_sr = RES_ERROR;
2653 fdtab[fd].state = FD_STERROR;
2654 }
2655
willy tarreau5cbea6f2005-12-17 12:48:26 +01002656 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002657 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002658 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2659 else
2660 tv_eternity(&s->srexpire);
2661
2662 task_wakeup(&rq, t);
2663 }
willy tarreau0f7af912005-12-17 12:21:26 +01002664
willy tarreau0f7af912005-12-17 12:21:26 +01002665 return 0;
2666}
2667
2668/*
2669 * this function is called on a write event from a client socket.
2670 * It returns 0.
2671 */
2672int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002673 struct task *t = fdtab[fd].owner;
2674 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002675 struct buffer *b = s->rep;
2676 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002677
willy tarreau12350152005-12-18 01:03:27 +01002678#ifdef DEBUG_FULL
2679 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2680#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002681
2682 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002683 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002684 // max = BUFSIZE; BUG !!!!
2685 max = 0;
2686 }
2687 else if (b->r > b->w) {
2688 max = b->r - b->w;
2689 }
2690 else
2691 max = b->data + BUFSIZE - b->w;
2692
willy tarreau0f7af912005-12-17 12:21:26 +01002693 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002694 if (max == 0) {
2695 s->res_cw = RES_NULL;
2696 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002697 tv_eternity(&s->cwexpire);
2698 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002699 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002700 }
2701
willy tarreau3242e862005-12-17 12:27:53 +01002702#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002703 {
2704 int skerr;
2705 socklen_t lskerr = sizeof(skerr);
2706
2707 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2708 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002709 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002710 else
willy tarreau3242e862005-12-17 12:27:53 +01002711 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002712 }
willy tarreau3242e862005-12-17 12:27:53 +01002713#else
willy tarreau0f7af912005-12-17 12:21:26 +01002714 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002715#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002716
2717 if (ret > 0) {
2718 b->l -= ret;
2719 b->w += ret;
2720
2721 s->res_cw = RES_DATA;
2722
2723 if (b->w == b->data + BUFSIZE) {
2724 b->w = b->data; /* wrap around the buffer */
2725 }
2726 }
2727 else if (ret == 0) {
2728 /* nothing written, just make as if we were never called */
2729// s->res_cw = RES_NULL;
2730 return 0;
2731 }
2732 else if (errno == EAGAIN) /* ignore EAGAIN */
2733 return 0;
2734 else {
2735 s->res_cw = RES_ERROR;
2736 fdtab[fd].state = FD_STERROR;
2737 }
2738 }
2739 else {
2740 s->res_cw = RES_ERROR;
2741 fdtab[fd].state = FD_STERROR;
2742 }
2743
willy tarreaub1ff9db2005-12-17 13:51:03 +01002744 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002745 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002746 /* FIXME: to prevent the client from expiring read timeouts during writes,
2747 * we refresh it. A solution would be to merge read+write timeouts into a
2748 * unique one, although that needs some study particularly on full-duplex
2749 * TCP connections. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002750 s->crexpire = s->cwexpire;
2751 }
willy tarreau0f7af912005-12-17 12:21:26 +01002752 else
2753 tv_eternity(&s->cwexpire);
2754
willy tarreau5cbea6f2005-12-17 12:48:26 +01002755 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002756 return 0;
2757}
2758
2759
2760/*
2761 * this function is called on a write event from a server socket.
2762 * It returns 0.
2763 */
2764int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002765 struct task *t = fdtab[fd].owner;
2766 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002767 struct buffer *b = s->req;
2768 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002769
willy tarreau12350152005-12-18 01:03:27 +01002770#ifdef DEBUG_FULL
2771 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2772#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002773
2774 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002775 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002776 // max = BUFSIZE; BUG !!!!
2777 max = 0;
2778 }
2779 else if (b->r > b->w) {
2780 max = b->r - b->w;
2781 }
2782 else
2783 max = b->data + BUFSIZE - b->w;
2784
willy tarreau0f7af912005-12-17 12:21:26 +01002785 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002786 if (max == 0) {
2787 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002788 if (s->srv_state == SV_STCONN) {
2789 int skerr;
2790 socklen_t lskerr = sizeof(skerr);
2791 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2792 if (skerr) {
2793 s->res_sw = RES_ERROR;
2794 fdtab[fd].state = FD_STERROR;
2795 task_wakeup(&rq, t);
2796 tv_eternity(&s->swexpire);
2797 FD_CLR(fd, StaticWriteEvent);
2798 return 0;
2799 }
2800 }
2801
willy tarreau0f7af912005-12-17 12:21:26 +01002802 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002803 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002804 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002805 tv_eternity(&s->swexpire);
2806 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002807 return 0;
2808 }
2809
willy tarreau3242e862005-12-17 12:27:53 +01002810#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002811 {
2812 int skerr;
2813 socklen_t lskerr = sizeof(skerr);
2814 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2815 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002816 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002817 else
willy tarreau3242e862005-12-17 12:27:53 +01002818 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002819 }
willy tarreau3242e862005-12-17 12:27:53 +01002820#else
willy tarreau0f7af912005-12-17 12:21:26 +01002821 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002822#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002823 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002824 if (ret > 0) {
2825 b->l -= ret;
2826 b->w += ret;
2827
2828 s->res_sw = RES_DATA;
2829
2830 if (b->w == b->data + BUFSIZE) {
2831 b->w = b->data; /* wrap around the buffer */
2832 }
2833 }
2834 else if (ret == 0) {
2835 /* nothing written, just make as if we were never called */
2836 // s->res_sw = RES_NULL;
2837 return 0;
2838 }
2839 else if (errno == EAGAIN) /* ignore EAGAIN */
2840 return 0;
2841 else {
2842 s->res_sw = RES_ERROR;
2843 fdtab[fd].state = FD_STERROR;
2844 }
2845 }
2846 else {
2847 s->res_sw = RES_ERROR;
2848 fdtab[fd].state = FD_STERROR;
2849 }
2850
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002851 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2852 * otherwise it could loop indefinitely !
2853 */
2854 if (s->srv_state != SV_STCONN) {
2855 if (s->proxy->srvtimeout) {
2856 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002857 /* FIXME: to prevent the server from expiring read timeouts during writes,
2858 * we refresh it. A solution would be to merge read+write+connect timeouts
2859 * into a unique one since we don't mind expiring on read or write, and none
2860 * of them is enabled while waiting for connect(), although that needs some
2861 * study particularly on full-duplex TCP connections. */
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002862 s->srexpire = s->swexpire;
2863 }
2864 else
2865 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002866 }
willy tarreau0f7af912005-12-17 12:21:26 +01002867
willy tarreau5cbea6f2005-12-17 12:48:26 +01002868 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002869 return 0;
2870}
2871
2872
2873/*
willy tarreaue39cd132005-12-17 13:00:18 +01002874 * returns a message to the client ; the connection is shut down for read,
2875 * and the request is cleared so that no server connection can be initiated.
2876 * The client must be in a valid state for this (HEADER, DATA ...).
2877 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002878 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002879 */
2880void client_retnclose(struct session *s, int len, const char *msg) {
2881 FD_CLR(s->cli_fd, StaticReadEvent);
2882 FD_SET(s->cli_fd, StaticWriteEvent);
2883 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002884 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002885 shutdown(s->cli_fd, SHUT_RD);
2886 s->cli_state = CL_STSHUTR;
2887 strcpy(s->rep->data, msg);
2888 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002889 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002890 s->rep->r += len;
2891 s->req->l = 0;
2892}
2893
2894
2895/*
2896 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002897 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002898 */
2899void client_return(struct session *s, int len, const char *msg) {
2900 strcpy(s->rep->data, msg);
2901 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002902 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002903 s->rep->r += len;
2904 s->req->l = 0;
2905}
2906
willy tarreau9fe663a2005-12-17 13:02:59 +01002907/*
2908 * send a log for the session when we have enough info about it
2909 */
2910void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002911 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002912 struct proxy *p = s->proxy;
2913 int log;
2914 char *uri;
2915 char *pxid;
2916 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002917 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002918
2919 /* This is a first attempt at a better logging system.
2920 * For now, we rely on send_log() to provide the date, although it obviously
2921 * is the date of the log and not of the request, and most fields are not
2922 * computed.
2923 */
2924
willy tarreaua1598082005-12-17 13:08:06 +01002925 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002926
willy tarreau8a86dbf2005-12-18 00:45:59 +01002927 if (s->cli_addr.ss_family == AF_INET)
2928 inet_ntop(AF_INET,
2929 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2930 pn, sizeof(pn));
2931 else
2932 inet_ntop(AF_INET6,
2933 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2934 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002935
willy tarreauc1cae632005-12-17 14:12:23 +01002936 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002937 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002938 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002939
willy tarreauc1cae632005-12-17 14:12:23 +01002940 tm = localtime(&s->logs.tv_accept.tv_sec);
2941 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002942 char tmpline[MAX_SYSLOG_LEN], *h;
2943 int hdr;
2944
2945 h = tmpline;
2946 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2947 *(h++) = ' ';
2948 *(h++) = '{';
2949 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2950 if (hdr)
2951 *(h++) = '|';
2952 if (s->req_cap[hdr] != NULL)
2953 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2954 }
2955 *(h++) = '}';
2956 }
2957
2958 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2959 *(h++) = ' ';
2960 *(h++) = '{';
2961 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2962 if (hdr)
2963 *(h++) = '|';
2964 if (s->rsp_cap[hdr] != NULL)
2965 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2966 }
2967 *(h++) = '}';
2968 }
2969
2970 if (h < tmpline + sizeof(tmpline) - 4) {
2971 *(h++) = ' ';
2972 *(h++) = '"';
2973 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2974 *(h++) = '"';
2975 }
2976 *h = '\0';
2977
willy tarreau5e69b162006-05-12 19:49:37 +02002978 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 +01002979 pn,
2980 (s->cli_addr.ss_family == AF_INET) ?
2981 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2982 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002983 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2984 tm->tm_hour, tm->tm_min, tm->tm_sec,
2985 pxid, srv,
2986 s->logs.t_request,
willy tarreauf32f5242006-05-02 22:54:52 +02002987 (s->logs.t_queue >= 0) ? s->logs.t_queue - s->logs.t_request : -1,
2988 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreaua1598082005-12-17 13:08:06 +01002989 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002990 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2991 s->logs.status,
2992 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002993 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2994 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002995 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2996 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2997 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2998 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau5e69b162006-05-12 19:49:37 +02002999 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3000 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01003001 }
3002 else {
willy tarreau5f15c552006-05-13 18:37:04 +02003003 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 +01003004 pn,
3005 (s->cli_addr.ss_family == AF_INET) ?
3006 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3007 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01003008 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3009 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01003010 pxid, srv,
willy tarreau5f15c552006-05-13 18:37:04 +02003011 (s->logs.t_queue >= 0) ? s->logs.t_queue : -1,
3012 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003013 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3014 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01003015 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01003016 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreau5e69b162006-05-12 19:49:37 +02003017 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3018 s->logs.srv_queue_size, s->logs.prx_queue_size);
willy tarreaua1598082005-12-17 13:08:06 +01003019 }
3020
3021 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003022}
3023
willy tarreaue39cd132005-12-17 13:00:18 +01003024
3025/*
willy tarreau0f7af912005-12-17 12:21:26 +01003026 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01003027 * to an accept. It tries to accept as many connections as possible.
3028 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01003029 */
3030int event_accept(int fd) {
3031 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003032 struct session *s;
3033 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01003034 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01003035 int max_accept;
3036
3037 if (global.nbproc > 1)
3038 max_accept = 8; /* let other processes catch some connections too */
3039 else
3040 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003041
willy tarreauc2becdc2006-03-19 19:36:48 +01003042 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003043 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003044 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01003045
willy tarreaub1285d52005-12-18 01:20:14 +01003046 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
3047 switch (errno) {
3048 case EAGAIN:
3049 case EINTR:
3050 case ECONNABORTED:
3051 return 0; /* nothing more to accept */
3052 case ENFILE:
3053 send_log(p, LOG_EMERG,
3054 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
3055 p->id, maxfd);
3056 return 0;
3057 case EMFILE:
3058 send_log(p, LOG_EMERG,
3059 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
3060 p->id, maxfd);
3061 return 0;
3062 case ENOBUFS:
3063 case ENOMEM:
3064 send_log(p, LOG_EMERG,
3065 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
3066 p->id, maxfd);
3067 return 0;
3068 default:
3069 return 0;
3070 }
3071 }
willy tarreau0f7af912005-12-17 12:21:26 +01003072
willy tarreau5cbea6f2005-12-17 12:48:26 +01003073 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
3074 Alert("out of memory in event_accept().\n");
3075 FD_CLR(fd, StaticReadEvent);
3076 p->state = PR_STIDLE;
3077 close(cfd);
3078 return 0;
3079 }
willy tarreau0f7af912005-12-17 12:21:26 +01003080
willy tarreaub1285d52005-12-18 01:20:14 +01003081 /* if this session comes from a known monitoring system, we want to ignore
3082 * it as soon as possible, which means closing it immediately for TCP.
3083 */
3084 s->flags = 0;
3085 if (addr.ss_family == AF_INET &&
3086 p->mon_mask.s_addr &&
3087 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
3088 if (p->mode == PR_MODE_TCP) {
3089 close(cfd);
3090 pool_free(session, s);
3091 continue;
3092 }
3093 s->flags |= SN_MONITOR;
3094 }
3095
willy tarreau5cbea6f2005-12-17 12:48:26 +01003096 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3097 Alert("out of memory in event_accept().\n");
3098 FD_CLR(fd, StaticReadEvent);
3099 p->state = PR_STIDLE;
3100 close(cfd);
3101 pool_free(session, s);
3102 return 0;
3103 }
willy tarreau0f7af912005-12-17 12:21:26 +01003104
willy tarreau5cbea6f2005-12-17 12:48:26 +01003105 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01003106 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003107 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
3108 close(cfd);
3109 pool_free(task, t);
3110 pool_free(session, s);
3111 return 0;
3112 }
willy tarreau0f7af912005-12-17 12:21:26 +01003113
willy tarreau5cbea6f2005-12-17 12:48:26 +01003114 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
3115 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
3116 (char *) &one, sizeof(one)) == -1)) {
3117 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
3118 close(cfd);
3119 pool_free(task, t);
3120 pool_free(session, s);
3121 return 0;
3122 }
willy tarreau0f7af912005-12-17 12:21:26 +01003123
willy tarreaub952e1d2005-12-18 01:31:20 +01003124 if (p->options & PR_O_TCP_CLI_KA)
3125 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
3126
willy tarreau9fe663a2005-12-17 13:02:59 +01003127 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02003128 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
willy tarreau9fe663a2005-12-17 13:02:59 +01003129 t->state = TASK_IDLE;
3130 t->process = process_session;
3131 t->context = s;
3132
3133 s->task = t;
3134 s->proxy = p;
3135 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
3136 s->srv_state = SV_STIDLE;
3137 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01003138
willy tarreau9fe663a2005-12-17 13:02:59 +01003139 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
3140 s->cli_fd = cfd;
3141 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003142 s->srv = NULL;
Willy TARREAU1a71cc12006-05-14 09:10:03 +02003143 s->pend_pos = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01003144 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01003145
willy tarreaub1285d52005-12-18 01:20:14 +01003146 if (s->flags & SN_MONITOR)
3147 s->logs.logwait = 0;
3148 else
3149 s->logs.logwait = p->to_log;
3150
willy tarreaua1598082005-12-17 13:08:06 +01003151 s->logs.tv_accept = now;
3152 s->logs.t_request = -1;
willy tarreauf32f5242006-05-02 22:54:52 +02003153 s->logs.t_queue = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003154 s->logs.t_connect = -1;
3155 s->logs.t_data = -1;
3156 s->logs.t_close = 0;
3157 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01003158 s->logs.cli_cookie = NULL;
3159 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01003160 s->logs.status = -1;
3161 s->logs.bytes = 0;
willy tarreau5e69b162006-05-12 19:49:37 +02003162 s->logs.prx_queue_size = 0; /* we get the number of pending conns before us */
3163 s->logs.srv_queue_size = 0; /* we will get this number soon */
willy tarreau9fe663a2005-12-17 13:02:59 +01003164
willy tarreau2f6ba652005-12-17 13:57:42 +01003165 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02003166 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01003167
willy tarreau4302f492005-12-18 01:00:37 +01003168 if (p->nb_req_cap > 0) {
3169 if ((s->req_cap =
3170 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
3171 == NULL) { /* no memory */
3172 close(cfd); /* nothing can be done for this fd without memory */
3173 pool_free(task, t);
3174 pool_free(session, s);
3175 return 0;
3176 }
3177 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
3178 }
3179 else
3180 s->req_cap = NULL;
3181
3182 if (p->nb_rsp_cap > 0) {
3183 if ((s->rsp_cap =
3184 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
3185 == NULL) { /* no memory */
3186 if (s->req_cap != NULL)
3187 pool_free_to(p->req_cap_pool, s->req_cap);
3188 close(cfd); /* nothing can be done for this fd without memory */
3189 pool_free(task, t);
3190 pool_free(session, s);
3191 return 0;
3192 }
3193 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
3194 }
3195 else
3196 s->rsp_cap = NULL;
3197
willy tarreau5cbea6f2005-12-17 12:48:26 +01003198 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
3199 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003200 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003201 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01003202
willy tarreau8a86dbf2005-12-18 00:45:59 +01003203 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003204 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003205 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003206 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01003207
willy tarreau9fe663a2005-12-17 13:02:59 +01003208 if (p->to_log) {
3209 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01003210 if (s->logs.logwait & LW_CLIP)
3211 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01003212 sess_log(s);
3213 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01003214 else if (s->cli_addr.ss_family == AF_INET) {
3215 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
3216 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
3217 sn, sizeof(sn)) &&
3218 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3219 pn, sizeof(pn))) {
3220 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3221 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
3222 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
3223 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3224 }
3225 }
3226 else {
3227 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
3228 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
3229 sn, sizeof(sn)) &&
3230 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
3231 pn, sizeof(pn))) {
3232 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3233 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
3234 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
3235 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3236 }
3237 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003238 }
willy tarreau0f7af912005-12-17 12:21:26 +01003239
willy tarreau982249e2005-12-18 00:57:06 +01003240 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01003241 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003242 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01003243 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01003244 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003245 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003246 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01003247 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01003248
willy tarreau8a86dbf2005-12-18 00:45:59 +01003249 if (s->cli_addr.ss_family == AF_INET) {
3250 char pn[INET_ADDRSTRLEN];
3251 inet_ntop(AF_INET,
3252 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3253 pn, sizeof(pn));
3254
3255 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3256 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3257 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
3258 }
3259 else {
3260 char pn[INET6_ADDRSTRLEN];
3261 inet_ntop(AF_INET6,
3262 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3263 pn, sizeof(pn));
3264
3265 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3266 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3267 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3268 }
3269
willy tarreauef900ab2005-12-17 12:52:52 +01003270 write(1, trash, len);
3271 }
willy tarreau0f7af912005-12-17 12:21:26 +01003272
willy tarreau5cbea6f2005-12-17 12:48:26 +01003273 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003274 if (s->rsp_cap != NULL)
3275 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3276 if (s->req_cap != NULL)
3277 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003278 close(cfd); /* nothing can be done for this fd without memory */
3279 pool_free(task, t);
3280 pool_free(session, s);
3281 return 0;
3282 }
willy tarreau4302f492005-12-18 01:00:37 +01003283
willy tarreau5cbea6f2005-12-17 12:48:26 +01003284 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003285 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003286 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3287 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003288 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003289 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003290
willy tarreau5cbea6f2005-12-17 12:48:26 +01003291 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3292 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003293 if (s->rsp_cap != NULL)
3294 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3295 if (s->req_cap != NULL)
3296 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003297 close(cfd); /* nothing can be done for this fd without memory */
3298 pool_free(task, t);
3299 pool_free(session, s);
3300 return 0;
3301 }
3302 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003303 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003304 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 +01003305
willy tarreau5cbea6f2005-12-17 12:48:26 +01003306 fdtab[cfd].read = &event_cli_read;
3307 fdtab[cfd].write = &event_cli_write;
3308 fdtab[cfd].owner = t;
3309 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003310
willy tarreaub1285d52005-12-18 01:20:14 +01003311 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3312 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3313 /* Either we got a request from a monitoring system on an HTTP instance,
3314 * or we're in health check mode with the 'httpchk' option enabled. In
3315 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3316 */
3317 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3318 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3319 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003320 }
3321 else {
3322 FD_SET(cfd, StaticReadEvent);
3323 }
3324
willy tarreaub952e1d2005-12-18 01:31:20 +01003325#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3326 if (PrevReadEvent) {
3327 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3328 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3329 }
3330#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003331 fd_insert(cfd);
3332
3333 tv_eternity(&s->cnexpire);
3334 tv_eternity(&s->srexpire);
3335 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003336 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003337 tv_eternity(&s->cwexpire);
3338
willy tarreaub1285d52005-12-18 01:20:14 +01003339 if (s->proxy->clitimeout) {
3340 if (FD_ISSET(cfd, StaticReadEvent))
3341 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3342 if (FD_ISSET(cfd, StaticWriteEvent))
3343 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3344 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003345
willy tarreaub1285d52005-12-18 01:20:14 +01003346 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003347
3348 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003349
3350 if (p->mode != PR_MODE_HEALTH)
3351 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003352
3353 p->nbconn++;
3354 actconn++;
3355 totalconn++;
3356
willy tarreaub952e1d2005-12-18 01:31:20 +01003357 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003358 } /* end of while (p->nbconn < p->maxconn) */
3359 return 0;
3360}
willy tarreau0f7af912005-12-17 12:21:26 +01003361
willy tarreau0f7af912005-12-17 12:21:26 +01003362
willy tarreau5cbea6f2005-12-17 12:48:26 +01003363/*
3364 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003365 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3366 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003367 * or -1 if an error occured.
3368 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003369int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003370 struct task *t = fdtab[fd].owner;
3371 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003372 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003373 socklen_t lskerr = sizeof(skerr);
3374
willy tarreau05be12b2006-03-19 19:35:00 +01003375 skerr = 1;
3376 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3377 || (skerr != 0)) {
3378 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003379 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003380 fdtab[fd].state = FD_STERROR;
3381 FD_CLR(fd, StaticWriteEvent);
3382 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003383 else if (s->result != -1) {
3384 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003385 if (s->proxy->options & PR_O_HTTP_CHK) {
3386 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003387 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003388 * so we'll send the request, and won't wake the checker up now.
3389 */
3390#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003391 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003392#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003393 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003394#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003395 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003396 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3397 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3398 return 0;
3399 }
willy tarreau05be12b2006-03-19 19:35:00 +01003400 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003401 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003402 FD_CLR(fd, StaticWriteEvent);
3403 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003404 }
3405 else {
3406 /* good TCP connection is enough */
3407 s->result = 1;
3408 }
3409 }
3410
3411 task_wakeup(&rq, t);
3412 return 0;
3413}
3414
willy tarreau0f7af912005-12-17 12:21:26 +01003415
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003416/*
3417 * This function is used only for server health-checks. It handles
3418 * the server's reply to an HTTP request. It returns 1 if the server replies
3419 * 2xx or 3xx (valid responses), or -1 in other cases.
3420 */
3421int event_srv_chk_r(int fd) {
3422 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003423 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003424 struct task *t = fdtab[fd].owner;
3425 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003426 int skerr;
3427 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003428
willy tarreaua4a583a2005-12-18 01:39:19 +01003429 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003430
willy tarreau05be12b2006-03-19 19:35:00 +01003431 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3432 if (!skerr) {
3433#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003434 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003435#else
willy tarreau05be12b2006-03-19 19:35:00 +01003436 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3437 * but the connection was closed on the remote end. Fortunately, recv still
3438 * works correctly and we don't need to do the getsockopt() on linux.
3439 */
3440 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003441#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003442
3443 if ((len >= sizeof("HTTP/1.0 000")) &&
3444 !memcmp(reply, "HTTP/1.", 7) &&
3445 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3446 result = 1;
3447 }
3448
3449 if (result == -1)
3450 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003451
3452 if (s->result != -1)
3453 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003454
3455 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003456 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003457 return 0;
3458}
3459
3460
3461/*
3462 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3463 * and moves <end> just after the end of <str>.
3464 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3465 * the shift value (positive or negative) is returned.
3466 * If there's no space left, the move is not done.
3467 *
3468 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003469int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003470 int delta;
3471 int len;
3472
3473 len = strlen(str);
3474 delta = len - (end - pos);
3475
3476 if (delta + b->r >= b->data + BUFSIZE)
3477 return 0; /* no space left */
3478
3479 /* first, protect the end of the buffer */
3480 memmove(end + delta, end, b->data + b->l - end);
3481
3482 /* now, copy str over pos */
3483 memcpy(pos, str,len);
3484
willy tarreau5cbea6f2005-12-17 12:48:26 +01003485 /* we only move data after the displaced zone */
3486 if (b->r > pos) b->r += delta;
3487 if (b->w > pos) b->w += delta;
3488 if (b->h > pos) b->h += delta;
3489 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003490 b->l += delta;
3491
3492 return delta;
3493}
3494
willy tarreau8337c6b2005-12-17 13:41:01 +01003495/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003496 * len is 0.
3497 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003498int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003499 int delta;
3500
3501 delta = len - (end - pos);
3502
3503 if (delta + b->r >= b->data + BUFSIZE)
3504 return 0; /* no space left */
3505
Willy TARREAUe78ae262006-01-08 01:24:12 +01003506 if (b->data + b->l < end)
3507 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3508 return 0;
3509
willy tarreau0f7af912005-12-17 12:21:26 +01003510 /* first, protect the end of the buffer */
3511 memmove(end + delta, end, b->data + b->l - end);
3512
3513 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003514 if (len)
3515 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003516
willy tarreau5cbea6f2005-12-17 12:48:26 +01003517 /* we only move data after the displaced zone */
3518 if (b->r > pos) b->r += delta;
3519 if (b->w > pos) b->w += delta;
3520 if (b->h > pos) b->h += delta;
3521 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003522 b->l += delta;
3523
3524 return delta;
3525}
3526
3527
3528int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3529 char *old_dst = dst;
3530
3531 while (*str) {
3532 if (*str == '\\') {
3533 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003534 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003535 int len, num;
3536
3537 num = *str - '0';
3538 str++;
3539
willy tarreau8a86dbf2005-12-18 00:45:59 +01003540 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003541 len = matches[num].rm_eo - matches[num].rm_so;
3542 memcpy(dst, src + matches[num].rm_so, len);
3543 dst += len;
3544 }
3545
3546 }
3547 else if (*str == 'x') {
3548 unsigned char hex1, hex2;
3549 str++;
3550
willy tarreauc1f47532005-12-18 01:08:26 +01003551 hex1 = toupper(*str++) - '0';
3552 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003553
3554 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3555 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3556 *dst++ = (hex1<<4) + hex2;
3557 }
3558 else
3559 *dst++ = *str++;
3560 }
3561 else
3562 *dst++ = *str++;
3563 }
3564 *dst = 0;
3565 return dst - old_dst;
3566}
3567
willy tarreauc1f47532005-12-18 01:08:26 +01003568static int ishex(char s)
3569{
3570 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3571}
3572
3573/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3574char *check_replace_string(char *str)
3575{
3576 char *err = NULL;
3577 while (*str) {
3578 if (*str == '\\') {
3579 err = str; /* in case of a backslash, we return the pointer to it */
3580 str++;
3581 if (!*str)
3582 return err;
3583 else if (isdigit((int)*str))
3584 err = NULL;
3585 else if (*str == 'x') {
3586 str++;
3587 if (!ishex(*str))
3588 return err;
3589 str++;
3590 if (!ishex(*str))
3591 return err;
3592 err = NULL;
3593 }
3594 else {
3595 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3596 err = NULL;
3597 }
3598 }
3599 str++;
3600 }
3601 return err;
3602}
3603
3604
willy tarreau9fe663a2005-12-17 13:02:59 +01003605
willy tarreau0f7af912005-12-17 12:21:26 +01003606/*
3607 * manages the client FSM and its socket. BTW, it also tries to handle the
3608 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3609 * 0 else.
3610 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003611int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003612 int s = t->srv_state;
3613 int c = t->cli_state;
3614 struct buffer *req = t->req;
3615 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003616 int method_checked = 0;
3617 appsess *asession_temp = NULL;
3618 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003619
willy tarreau750a4722005-12-17 13:21:24 +01003620#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003621 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3622 cli_stnames[c], srv_stnames[s],
3623 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3624 t->crexpire.tv_sec, t->crexpire.tv_usec,
3625 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003626#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003627 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3628 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3629 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3630 //);
3631 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003632 /* now parse the partial (or complete) headers */
3633 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3634 char *ptr;
3635 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003636 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003637
willy tarreau5cbea6f2005-12-17 12:48:26 +01003638 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003639
willy tarreau0f7af912005-12-17 12:21:26 +01003640 /* look for the end of the current header */
3641 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3642 ptr++;
3643
willy tarreau5cbea6f2005-12-17 12:48:26 +01003644 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003645 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02003646
3647 /*
3648 * first, let's check that it's not a leading empty line, in
3649 * which case we'll ignore and remove it (according to RFC2616).
3650 */
3651 if (req->h == req->data) {
3652 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3653 if (ptr > req->r - 2) {
3654 /* this is a partial header, let's wait for more to come */
3655 req->lr = ptr;
3656 break;
3657 }
3658
3659 /* now we know that *ptr is either \r or \n,
3660 * and that there are at least 1 char after it.
3661 */
3662 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3663 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3664 else
3665 req->lr = ptr + 2; /* \r\n or \n\r */
3666 /* ignore empty leading lines */
3667 buffer_replace2(req, req->h, req->lr, NULL, 0);
3668 req->h = req->lr;
3669 continue;
3670 }
3671
willy tarreau5cbea6f2005-12-17 12:48:26 +01003672 /* we can only get here after an end of headers */
3673 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003674
willy tarreaue39cd132005-12-17 13:00:18 +01003675 if (t->flags & SN_CLDENY) {
3676 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003677 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003678 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003679 if (!(t->flags & SN_ERR_MASK))
3680 t->flags |= SN_ERR_PRXCOND;
3681 if (!(t->flags & SN_FINST_MASK))
3682 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003683 return 1;
3684 }
3685
willy tarreau5cbea6f2005-12-17 12:48:26 +01003686 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003687 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3688 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003689 }
willy tarreau0f7af912005-12-17 12:21:26 +01003690
willy tarreau9fe663a2005-12-17 13:02:59 +01003691 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003692 if (t->cli_addr.ss_family == AF_INET) {
3693 unsigned char *pn;
3694 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3695 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3696 pn[0], pn[1], pn[2], pn[3]);
3697 buffer_replace2(req, req->h, req->h, trash, len);
3698 }
3699 else if (t->cli_addr.ss_family == AF_INET6) {
3700 char pn[INET6_ADDRSTRLEN];
3701 inet_ntop(AF_INET6,
3702 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3703 pn, sizeof(pn));
3704 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3705 buffer_replace2(req, req->h, req->h, trash, len);
3706 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003707 }
3708
willy tarreau25c4ea52005-12-18 00:49:49 +01003709 /* add a "connection: close" line if needed */
3710 if (t->proxy->options & PR_O_HTTP_CLOSE)
3711 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3712
willy tarreau982249e2005-12-18 00:57:06 +01003713 if (!memcmp(req->data, "POST ", 5)) {
3714 /* this is a POST request, which is not cacheable by default */
3715 t->flags |= SN_POST;
3716 }
willy tarreaucd878942005-12-17 13:27:43 +01003717
willy tarreau5cbea6f2005-12-17 12:48:26 +01003718 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003719 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003720
willy tarreau750a4722005-12-17 13:21:24 +01003721 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003722 /* FIXME: we'll set the client in a wait state while we try to
3723 * connect to the server. Is this really needed ? wouldn't it be
willy tarreau0889c962006-04-24 14:36:48 +02003724 * better to release the maximum of system buffers instead ?
3725 * The solution is to enable the FD but set its time-out to
3726 * eternity as long as the server-side does not enable data xfer.
3727 * CL_STDATA also has to take care of this, which is done below.
3728 */
willy tarreauef900ab2005-12-17 12:52:52 +01003729 //FD_CLR(t->cli_fd, StaticReadEvent);
3730 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003731
3732 /* FIXME: if we break here (as up to 1.1.23), having the client
3733 * shutdown its connection can lead to an abort further.
3734 * it's better to either return 1 or even jump directly to the
3735 * data state which will save one schedule.
3736 */
3737 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003738
3739 if (!t->proxy->clitimeout ||
3740 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3741 /* If the client has no timeout, or if the server is not ready yet,
3742 * and we know for sure that it can expire, then it's cleaner to
3743 * disable the timeout on the client side so that too low values
3744 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003745 *
3746 * FIXME-20050705: the server needs a way to re-enable this time-out
3747 * when it switches its state, otherwise a client can stay connected
3748 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003749 */
3750 tv_eternity(&t->crexpire);
3751
willy tarreau197e8ec2005-12-17 14:10:59 +01003752 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003753 }
willy tarreau0f7af912005-12-17 12:21:26 +01003754
Willy TARREAU13032e72006-03-12 17:31:45 +01003755 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3756 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003757 /* this is a partial header, let's wait for more to come */
3758 req->lr = ptr;
3759 break;
3760 }
willy tarreau0f7af912005-12-17 12:21:26 +01003761
willy tarreau5cbea6f2005-12-17 12:48:26 +01003762 /* now we know that *ptr is either \r or \n,
3763 * and that there are at least 1 char after it.
3764 */
3765 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3766 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3767 else
3768 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003769
willy tarreau5cbea6f2005-12-17 12:48:26 +01003770 /*
3771 * now we know that we have a full header ; we can do whatever
3772 * we want with these pointers :
3773 * req->h = beginning of header
3774 * ptr = end of header (first \r or \n)
3775 * req->lr = beginning of next line (next rep->h)
3776 * req->r = end of data (not used at this stage)
3777 */
willy tarreau0f7af912005-12-17 12:21:26 +01003778
willy tarreau12350152005-12-18 01:03:27 +01003779 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3780 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3781 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3782
3783 /* skip ; */
3784 request_line++;
3785
3786 /* look if we have a jsessionid */
3787
3788 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3789
3790 /* skip jsessionid= */
3791 request_line += t->proxy->appsession_name_len + 1;
3792
3793 /* First try if we allready have an appsession */
3794 asession_temp = &local_asession;
3795
3796 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3797 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3798 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3799 return 0;
3800 }
3801
3802 /* Copy the sessionid */
3803 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3804 asession_temp->sessid[t->proxy->appsession_len] = 0;
3805 asession_temp->serverid = NULL;
3806
3807 /* only do insert, if lookup fails */
3808 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3809 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3810 Alert("Not enough memory process_cli():asession:calloc().\n");
3811 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3812 return 0;
3813 }
3814 asession_temp->sessid = local_asession.sessid;
3815 asession_temp->serverid = local_asession.serverid;
3816 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003817 } /* end if (chtbl_lookup()) */
3818 else {
willy tarreau12350152005-12-18 01:03:27 +01003819 /*free wasted memory;*/
3820 pool_free_to(apools.sessid, local_asession.sessid);
3821 }
3822
3823 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3824 asession_temp->request_count++;
3825
3826#if defined(DEBUG_HASH)
3827 print_table(&(t->proxy->htbl_proxy));
3828#endif
3829
3830 if (asession_temp->serverid == NULL) {
3831 Alert("Found Application Session without matching server.\n");
3832 } else {
3833 struct server *srv = t->proxy->srv;
3834 while (srv) {
3835 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3836 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3837 /* we found the server and it's usable */
3838 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02003839 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01003840 t->srv = srv;
3841 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003842 } else {
willy tarreau12350152005-12-18 01:03:27 +01003843 t->flags &= ~SN_CK_MASK;
3844 t->flags |= SN_CK_DOWN;
3845 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003846 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003847 srv = srv->next;
3848 }/* end while(srv) */
3849 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003850 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003851 else {
3852 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3853 }
willy tarreau598da412005-12-18 01:07:29 +01003854 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003855 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003856 else{
3857 //printf("No Methode-Header with Session-String\n");
3858 }
3859
willy tarreau8337c6b2005-12-17 13:41:01 +01003860 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003861 /* we have a complete HTTP request that we must log */
3862 int urilen;
3863
willy tarreaua1598082005-12-17 13:08:06 +01003864 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003865 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003866 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003867 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003868 if (!(t->flags & SN_ERR_MASK))
3869 t->flags |= SN_ERR_PRXCOND;
3870 if (!(t->flags & SN_FINST_MASK))
3871 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003872 return 1;
3873 }
3874
3875 urilen = ptr - req->h;
3876 if (urilen >= REQURI_LEN)
3877 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003878 memcpy(t->logs.uri, req->h, urilen);
3879 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003880
willy tarreaua1598082005-12-17 13:08:06 +01003881 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003882 sess_log(t);
3883 }
willy tarreau4302f492005-12-18 01:00:37 +01003884 else if (t->logs.logwait & LW_REQHDR) {
3885 struct cap_hdr *h;
3886 int len;
3887 for (h = t->proxy->req_cap; h; h = h->next) {
3888 if ((h->namelen + 2 <= ptr - req->h) &&
3889 (req->h[h->namelen] == ':') &&
3890 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3891
3892 if (t->req_cap[h->index] == NULL)
3893 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3894
3895 len = ptr - (req->h + h->namelen + 2);
3896 if (len > h->len)
3897 len = h->len;
3898
3899 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3900 t->req_cap[h->index][len]=0;
3901 }
3902 }
3903
3904 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003905
willy tarreau5cbea6f2005-12-17 12:48:26 +01003906 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003907
willy tarreau982249e2005-12-18 00:57:06 +01003908 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003909 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003910 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 +01003911 max = ptr - req->h;
3912 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003913 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003914 trash[len++] = '\n';
3915 write(1, trash, len);
3916 }
willy tarreau0f7af912005-12-17 12:21:26 +01003917
willy tarreau25c4ea52005-12-18 00:49:49 +01003918
3919 /* remove "connection: " if needed */
3920 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3921 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3922 delete_header = 1;
3923 }
3924
willy tarreau5cbea6f2005-12-17 12:48:26 +01003925 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003926 if (!delete_header && t->proxy->req_exp != NULL
3927 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003928 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003929 char term;
3930
3931 term = *ptr;
3932 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003933 exp = t->proxy->req_exp;
3934 do {
3935 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3936 switch (exp->action) {
3937 case ACT_ALLOW:
3938 if (!(t->flags & SN_CLDENY))
3939 t->flags |= SN_CLALLOW;
3940 break;
3941 case ACT_REPLACE:
3942 if (!(t->flags & SN_CLDENY)) {
3943 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3944 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3945 }
3946 break;
3947 case ACT_REMOVE:
3948 if (!(t->flags & SN_CLDENY))
3949 delete_header = 1;
3950 break;
3951 case ACT_DENY:
3952 if (!(t->flags & SN_CLALLOW))
3953 t->flags |= SN_CLDENY;
3954 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003955 case ACT_PASS: /* we simply don't deny this one */
3956 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003957 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003958 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003959 }
willy tarreaue39cd132005-12-17 13:00:18 +01003960 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003961 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003962 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003963
willy tarreau240afa62005-12-17 13:14:35 +01003964 /* Now look for cookies. Conforming to RFC2109, we have to support
3965 * attributes whose name begin with a '$', and associate them with
3966 * the right cookie, if we want to delete this cookie.
3967 * So there are 3 cases for each cookie read :
3968 * 1) it's a special attribute, beginning with a '$' : ignore it.
3969 * 2) it's a server id cookie that we *MAY* want to delete : save
3970 * some pointers on it (last semi-colon, beginning of cookie...)
3971 * 3) it's an application cookie : we *MAY* have to delete a previous
3972 * "special" cookie.
3973 * At the end of loop, if a "special" cookie remains, we may have to
3974 * remove it. If no application cookie persists in the header, we
3975 * *MUST* delete it
3976 */
willy tarreau12350152005-12-18 01:03:27 +01003977 if (!delete_header &&
3978 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003979 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003980 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003981 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003982 char *del_colon, *del_cookie, *colon;
3983 int app_cookies;
3984
willy tarreau5cbea6f2005-12-17 12:48:26 +01003985 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003986 colon = p1;
3987 /* del_cookie == NULL => nothing to be deleted */
3988 del_colon = del_cookie = NULL;
3989 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003990
3991 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003992 /* skip spaces and colons, but keep an eye on these ones */
3993 while (p1 < ptr) {
3994 if (*p1 == ';' || *p1 == ',')
3995 colon = p1;
3996 else if (!isspace((int)*p1))
3997 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003998 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003999 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004000
4001 if (p1 == ptr)
4002 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004003
4004 /* p1 is at the beginning of the cookie name */
4005 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01004006 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004007 p2++;
4008
4009 if (p2 == ptr)
4010 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004011
4012 p3 = p2 + 1; /* skips the '=' sign */
4013 if (p3 == ptr)
4014 break;
4015
willy tarreau240afa62005-12-17 13:14:35 +01004016 p4 = p3;
4017 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004018 p4++;
4019
4020 /* here, we have the cookie name between p1 and p2,
4021 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01004022 * we can process it :
4023 *
4024 * Cookie: NAME=VALUE;
4025 * | || || |
4026 * | || || +--> p4
4027 * | || |+-------> p3
4028 * | || +--------> p2
4029 * | |+------------> p1
4030 * | +-------------> colon
4031 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01004032 */
4033
willy tarreau240afa62005-12-17 13:14:35 +01004034 if (*p1 == '$') {
4035 /* skip this one */
4036 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004037 else {
4038 /* first, let's see if we want to capture it */
4039 if (t->proxy->capture_name != NULL &&
4040 t->logs.cli_cookie == NULL &&
4041 (p4 - p1 >= t->proxy->capture_namelen) &&
4042 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4043 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004044
willy tarreau8337c6b2005-12-17 13:41:01 +01004045 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4046 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01004047 } else {
4048 if (log_len > t->proxy->capture_len)
4049 log_len = t->proxy->capture_len;
4050 memcpy(t->logs.cli_cookie, p1, log_len);
4051 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01004052 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004053 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004054
4055 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4056 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
4057 /* Cool... it's the right one */
4058 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01004059 char *delim;
4060
4061 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4062 * have the server ID betweek p3 and delim, and the original cookie between
4063 * delim+1 and p4. Otherwise, delim==p4 :
4064 *
4065 * Cookie: NAME=SRV~VALUE;
4066 * | || || | |
4067 * | || || | +--> p4
4068 * | || || +--------> delim
4069 * | || |+-----------> p3
4070 * | || +------------> p2
4071 * | |+----------------> p1
4072 * | +-----------------> colon
4073 * +------------------------> req->h
4074 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004075
willy tarreau0174f312005-12-18 01:02:42 +01004076 if (t->proxy->options & PR_O_COOK_PFX) {
4077 for (delim = p3; delim < p4; delim++)
4078 if (*delim == COOKIE_DELIM)
4079 break;
4080 }
4081 else
4082 delim = p4;
4083
4084
4085 /* Here, we'll look for the first running server which supports the cookie.
4086 * This allows to share a same cookie between several servers, for example
4087 * to dedicate backup servers to specific servers only.
willy tarreau422bb2e2006-05-10 04:27:21 +02004088 * However, to prevent clients from sticking to cookie-less backup server
4089 * when they have incidentely learned an empty cookie, we simply ignore
4090 * empty cookies and mark them as invalid.
willy tarreau0174f312005-12-18 01:02:42 +01004091 */
willy tarreau422bb2e2006-05-10 04:27:21 +02004092 if (delim == p3)
4093 srv = NULL;
4094
willy tarreau0174f312005-12-18 01:02:42 +01004095 while (srv) {
4096 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
4097 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4098 /* we found the server and it's usable */
4099 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004100 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau0174f312005-12-18 01:02:42 +01004101 t->srv = srv;
4102 break;
willy tarreau12350152005-12-18 01:03:27 +01004103 } else {
willy tarreau0174f312005-12-18 01:02:42 +01004104 /* we found a server, but it's down */
4105 t->flags &= ~SN_CK_MASK;
4106 t->flags |= SN_CK_DOWN;
4107 }
4108 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004109 srv = srv->next;
4110 }
4111
willy tarreau0174f312005-12-18 01:02:42 +01004112 if (!srv && !(t->flags & SN_CK_DOWN)) {
4113 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01004114 t->flags &= ~SN_CK_MASK;
4115 t->flags |= SN_CK_INVALID;
4116 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004117
willy tarreau0174f312005-12-18 01:02:42 +01004118 /* depending on the cookie mode, we may have to either :
4119 * - delete the complete cookie if we're in insert+indirect mode, so that
4120 * the server never sees it ;
4121 * - remove the server id from the cookie value, and tag the cookie as an
4122 * application cookie so that it does not get accidentely removed later,
4123 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01004124 */
willy tarreau0174f312005-12-18 01:02:42 +01004125 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
4126 buffer_replace2(req, p3, delim + 1, NULL, 0);
4127 p4 -= (delim + 1 - p3);
4128 ptr -= (delim + 1 - p3);
4129 del_cookie = del_colon = NULL;
4130 app_cookies++; /* protect the header from deletion */
4131 }
4132 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01004133 (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 +01004134 del_cookie = p1;
4135 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01004136 }
willy tarreau12350152005-12-18 01:03:27 +01004137 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01004138 /* now we know that we must keep this cookie since it's
4139 * not ours. But if we wanted to delete our cookie
4140 * earlier, we cannot remove the complete header, but we
4141 * can remove the previous block itself.
4142 */
4143 app_cookies++;
4144
4145 if (del_cookie != NULL) {
4146 buffer_replace2(req, del_cookie, p1, NULL, 0);
4147 p4 -= (p1 - del_cookie);
4148 ptr -= (p1 - del_cookie);
4149 del_cookie = del_colon = NULL;
4150 }
willy tarreau240afa62005-12-17 13:14:35 +01004151 }
willy tarreau12350152005-12-18 01:03:27 +01004152
4153 if ((t->proxy->appsession_name != NULL) &&
4154 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4155 /* first, let's see if the cookie is our appcookie*/
4156
4157 /* Cool... it's the right one */
4158
4159 asession_temp = &local_asession;
4160
4161 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4162 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4163 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4164 return 0;
4165 }
4166
4167 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4168 asession_temp->sessid[t->proxy->appsession_len] = 0;
4169 asession_temp->serverid = NULL;
4170
4171 /* only do insert, if lookup fails */
4172 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4173 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4174 Alert("Not enough memory process_cli():asession:calloc().\n");
4175 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4176 return 0;
4177 }
4178
4179 asession_temp->sessid = local_asession.sessid;
4180 asession_temp->serverid = local_asession.serverid;
4181 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4182 }
4183 else{
4184 /* free wasted memory */
4185 pool_free_to(apools.sessid, local_asession.sessid);
4186 }
4187
4188 if (asession_temp->serverid == NULL) {
4189 Alert("Found Application Session without matching server.\n");
4190 } else {
4191 struct server *srv = t->proxy->srv;
4192 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01004193 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01004194 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4195 /* we found the server and it's usable */
4196 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004197 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004198 t->srv = srv;
4199 break;
4200 } else {
4201 t->flags &= ~SN_CK_MASK;
4202 t->flags |= SN_CK_DOWN;
4203 }
4204 }
4205 srv = srv->next;
4206 }/* end while(srv) */
4207 }/* end else if server == NULL */
4208
4209 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01004210 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004211 }
willy tarreau240afa62005-12-17 13:14:35 +01004212
willy tarreau5cbea6f2005-12-17 12:48:26 +01004213 /* we'll have to look for another cookie ... */
4214 p1 = p4;
4215 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01004216
4217 /* There's no more cookie on this line.
4218 * We may have marked the last one(s) for deletion.
4219 * We must do this now in two ways :
4220 * - if there is no app cookie, we simply delete the header ;
4221 * - if there are app cookies, we must delete the end of the
4222 * string properly, including the colon/semi-colon before
4223 * the cookie name.
4224 */
4225 if (del_cookie != NULL) {
4226 if (app_cookies) {
4227 buffer_replace2(req, del_colon, ptr, NULL, 0);
4228 /* WARNING! <ptr> becomes invalid for now. If some code
4229 * below needs to rely on it before the end of the global
4230 * header loop, we need to correct it with this code :
4231 * ptr = del_colon;
4232 */
4233 }
4234 else
4235 delete_header = 1;
4236 }
4237 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004238
4239 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004240 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01004241 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01004242 }
willy tarreau240afa62005-12-17 13:14:35 +01004243 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
4244
willy tarreau5cbea6f2005-12-17 12:48:26 +01004245 req->h = req->lr;
4246 } /* while (req->lr < req->r) */
4247
4248 /* end of header processing (even if incomplete) */
4249
willy tarreauef900ab2005-12-17 12:52:52 +01004250 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4251 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4252 * full. We cannot loop here since event_cli_read will disable it only if
4253 * req->l == rlim-data
4254 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004255 FD_SET(t->cli_fd, StaticReadEvent);
4256 if (t->proxy->clitimeout)
4257 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4258 else
4259 tv_eternity(&t->crexpire);
4260 }
4261
willy tarreaue39cd132005-12-17 13:00:18 +01004262 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01004263 * won't be able to free more later, so the session will never terminate.
4264 */
willy tarreaue39cd132005-12-17 13:00:18 +01004265 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01004266 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01004267 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01004268 if (!(t->flags & SN_ERR_MASK))
4269 t->flags |= SN_ERR_PRXCOND;
4270 if (!(t->flags & SN_FINST_MASK))
4271 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004272 return 1;
4273 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004274 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004275 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004276 tv_eternity(&t->crexpire);
4277 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004278 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004279 if (!(t->flags & SN_ERR_MASK))
4280 t->flags |= SN_ERR_CLICL;
4281 if (!(t->flags & SN_FINST_MASK))
4282 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004283 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004284 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004285 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4286
4287 /* read timeout : give up with an error message.
4288 */
4289 t->logs.status = 408;
4290 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004291 if (!(t->flags & SN_ERR_MASK))
4292 t->flags |= SN_ERR_CLITO;
4293 if (!(t->flags & SN_FINST_MASK))
4294 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004295 return 1;
4296 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004297
4298 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004299 }
4300 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004301 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004302 /* FIXME: this error handling is partly buggy because we always report
4303 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4304 * or HEADER phase. BTW, it's not logical to expire the client while
4305 * we're waiting for the server to connect.
4306 */
willy tarreau0f7af912005-12-17 12:21:26 +01004307 /* read or write error */
4308 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004309 tv_eternity(&t->crexpire);
4310 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004311 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004312 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004313 if (!(t->flags & SN_ERR_MASK))
4314 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004315 if (!(t->flags & SN_FINST_MASK)) {
4316 if (t->pend_pos)
4317 t->flags |= SN_FINST_Q;
4318 else if (s == SV_STCONN)
4319 t->flags |= SN_FINST_C;
4320 else
4321 t->flags |= SN_FINST_D;
4322 }
willy tarreau0f7af912005-12-17 12:21:26 +01004323 return 1;
4324 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004325 /* last read, or end of server write */
4326 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004327 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004328 tv_eternity(&t->crexpire);
4329 shutdown(t->cli_fd, SHUT_RD);
4330 t->cli_state = CL_STSHUTR;
4331 return 1;
4332 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004333 /* last server read and buffer empty */
4334 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004335 FD_CLR(t->cli_fd, StaticWriteEvent);
4336 tv_eternity(&t->cwexpire);
4337 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004338 /* We must ensure that the read part is still alive when switching
4339 * to shutw */
4340 FD_SET(t->cli_fd, StaticReadEvent);
4341 if (t->proxy->clitimeout)
4342 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004343 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004344 //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 +01004345 return 1;
4346 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004347 /* read timeout */
4348 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4349 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004350 tv_eternity(&t->crexpire);
4351 shutdown(t->cli_fd, SHUT_RD);
4352 t->cli_state = CL_STSHUTR;
4353 if (!(t->flags & SN_ERR_MASK))
4354 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004355 if (!(t->flags & SN_FINST_MASK)) {
4356 if (t->pend_pos)
4357 t->flags |= SN_FINST_Q;
4358 else if (s == SV_STCONN)
4359 t->flags |= SN_FINST_C;
4360 else
4361 t->flags |= SN_FINST_D;
4362 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004363 return 1;
4364 }
4365 /* write timeout */
4366 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4367 FD_CLR(t->cli_fd, StaticWriteEvent);
4368 tv_eternity(&t->cwexpire);
4369 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004370 /* We must ensure that the read part is still alive when switching
4371 * to shutw */
4372 FD_SET(t->cli_fd, StaticReadEvent);
4373 if (t->proxy->clitimeout)
4374 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4375
willy tarreau036e1ce2005-12-17 13:46:33 +01004376 t->cli_state = CL_STSHUTW;
4377 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004378 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004379 if (!(t->flags & SN_FINST_MASK)) {
4380 if (t->pend_pos)
4381 t->flags |= SN_FINST_Q;
4382 else if (s == SV_STCONN)
4383 t->flags |= SN_FINST_C;
4384 else
4385 t->flags |= SN_FINST_D;
4386 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004387 return 1;
4388 }
willy tarreau0f7af912005-12-17 12:21:26 +01004389
willy tarreauc58fc692005-12-17 14:13:08 +01004390 if (req->l >= req->rlim - req->data) {
4391 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004392 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004393 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004394 FD_CLR(t->cli_fd, StaticReadEvent);
4395 tv_eternity(&t->crexpire);
4396 }
4397 }
4398 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004399 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004400 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4401 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004402 if (!t->proxy->clitimeout ||
4403 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4404 /* If the client has no timeout, or if the server not ready yet, and we
4405 * know for sure that it can expire, then it's cleaner to disable the
4406 * timeout on the client side so that too low values cannot make the
4407 * sessions abort too early.
4408 */
willy tarreau0f7af912005-12-17 12:21:26 +01004409 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004410 else
4411 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004412 }
4413 }
4414
4415 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004416 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004417 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4418 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4419 tv_eternity(&t->cwexpire);
4420 }
4421 }
4422 else { /* buffer not empty */
4423 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4424 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004425 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004426 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004427 /* FIXME: to prevent the client from expiring read timeouts during writes,
4428 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004429 t->crexpire = t->cwexpire;
4430 }
willy tarreau0f7af912005-12-17 12:21:26 +01004431 else
4432 tv_eternity(&t->cwexpire);
4433 }
4434 }
4435 return 0; /* other cases change nothing */
4436 }
4437 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004438 if (t->res_cw == RES_ERROR) {
4439 tv_eternity(&t->cwexpire);
4440 fd_delete(t->cli_fd);
4441 t->cli_state = CL_STCLOSE;
4442 if (!(t->flags & SN_ERR_MASK))
4443 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004444 if (!(t->flags & SN_FINST_MASK)) {
4445 if (t->pend_pos)
4446 t->flags |= SN_FINST_Q;
4447 else if (s == SV_STCONN)
4448 t->flags |= SN_FINST_C;
4449 else
4450 t->flags |= SN_FINST_D;
4451 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004452 return 1;
4453 }
4454 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004455 tv_eternity(&t->cwexpire);
4456 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004457 t->cli_state = CL_STCLOSE;
4458 return 1;
4459 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004460 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4461 tv_eternity(&t->cwexpire);
4462 fd_delete(t->cli_fd);
4463 t->cli_state = CL_STCLOSE;
4464 if (!(t->flags & SN_ERR_MASK))
4465 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004466 if (!(t->flags & SN_FINST_MASK)) {
4467 if (t->pend_pos)
4468 t->flags |= SN_FINST_Q;
4469 else if (s == SV_STCONN)
4470 t->flags |= SN_FINST_C;
4471 else
4472 t->flags |= SN_FINST_D;
4473 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004474 return 1;
4475 }
willy tarreau0f7af912005-12-17 12:21:26 +01004476 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004477 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004478 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4479 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4480 tv_eternity(&t->cwexpire);
4481 }
4482 }
4483 else { /* buffer not empty */
4484 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4485 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004486 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004487 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004488 /* FIXME: to prevent the client from expiring read timeouts during writes,
4489 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004490 t->crexpire = t->cwexpire;
4491 }
willy tarreau0f7af912005-12-17 12:21:26 +01004492 else
4493 tv_eternity(&t->cwexpire);
4494 }
4495 }
4496 return 0;
4497 }
4498 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004499 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004500 tv_eternity(&t->crexpire);
4501 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004502 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004503 if (!(t->flags & SN_ERR_MASK))
4504 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004505 if (!(t->flags & SN_FINST_MASK)) {
4506 if (t->pend_pos)
4507 t->flags |= SN_FINST_Q;
4508 else if (s == SV_STCONN)
4509 t->flags |= SN_FINST_C;
4510 else
4511 t->flags |= SN_FINST_D;
4512 }
willy tarreau0f7af912005-12-17 12:21:26 +01004513 return 1;
4514 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004515 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4516 tv_eternity(&t->crexpire);
4517 fd_delete(t->cli_fd);
4518 t->cli_state = CL_STCLOSE;
4519 return 1;
4520 }
4521 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4522 tv_eternity(&t->crexpire);
4523 fd_delete(t->cli_fd);
4524 t->cli_state = CL_STCLOSE;
4525 if (!(t->flags & SN_ERR_MASK))
4526 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004527 if (!(t->flags & SN_FINST_MASK)) {
4528 if (t->pend_pos)
4529 t->flags |= SN_FINST_Q;
4530 else if (s == SV_STCONN)
4531 t->flags |= SN_FINST_C;
4532 else
4533 t->flags |= SN_FINST_D;
4534 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004535 return 1;
4536 }
willy tarreauef900ab2005-12-17 12:52:52 +01004537 else if (req->l >= req->rlim - req->data) {
4538 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004539
4540 /* FIXME-20050705: is it possible for a client to maintain a session
4541 * after the timeout by sending more data after it receives a close ?
4542 */
4543
willy tarreau0f7af912005-12-17 12:21:26 +01004544 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004545 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004546 FD_CLR(t->cli_fd, StaticReadEvent);
4547 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004548 //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 +01004549 }
4550 }
4551 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004552 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004553 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4554 FD_SET(t->cli_fd, StaticReadEvent);
4555 if (t->proxy->clitimeout)
4556 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4557 else
4558 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004559 //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 +01004560 }
4561 }
4562 return 0;
4563 }
4564 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004565 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004566 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004567 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 +01004568 write(1, trash, len);
4569 }
4570 return 0;
4571 }
4572 return 0;
4573}
4574
willy tarreaudfece232006-05-02 00:19:57 +02004575/* This function turns the server state into the SV_STCLOSE, and sets
4576 * indicators accordingly. Note that if <status> is 0, no message is
4577 * returned.
4578 */
4579void srv_close_with_err(struct session *t, int err, int finst, int status, int msglen, char *msg) {
4580 t->srv_state = SV_STCLOSE;
4581 if (status > 0) {
4582 t->logs.status = status;
4583 if (t->proxy->mode == PR_MODE_HTTP)
4584 client_return(t, msglen, msg);
4585 }
4586 if (!(t->flags & SN_ERR_MASK))
4587 t->flags |= err;
4588 if (!(t->flags & SN_FINST_MASK))
4589 t->flags |= finst;
4590}
4591
4592/*
4593 * This function checks the retry count during the connect() job.
4594 * It updates the session's srv_state and retries, so that the caller knows
4595 * what it has to do. It uses the last connection error to set the log when
4596 * it expires. It returns 1 when it has expired, and 0 otherwise.
4597 */
4598int srv_count_retry_down(struct session *t, int conn_err) {
4599 /* we are in front of a retryable error */
4600 t->conn_retries--;
4601 if (t->conn_retries < 0) {
4602 /* if not retryable anymore, let's abort */
4603 tv_eternity(&t->cnexpire);
4604 srv_close_with_err(t, conn_err, SN_FINST_C,
4605 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4606
4607 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02004608 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02004609 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004610 if (may_dequeue_tasks(t->srv, t->proxy))
4611 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004612 return 1;
4613 }
4614 return 0;
4615}
willy tarreau0f7af912005-12-17 12:21:26 +01004616
4617/*
willy tarreaudfece232006-05-02 00:19:57 +02004618 * This function performs the retryable part of the connect() job.
4619 * It updates the session's srv_state and retries, so that the caller knows
4620 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
4621 * it needs to redispatch.
4622 */
4623int srv_retryable_connect(struct session *t) {
4624 int conn_err;
4625
4626 /* This loop ensures that we stop before the last retry in case of a
4627 * redispatchable server.
4628 */
4629 do {
4630 /* initiate a connection to the server */
4631 conn_err = connect_server(t);
4632 switch (conn_err) {
4633
4634 case SN_ERR_NONE:
4635 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4636 t->srv_state = SV_STCONN;
4637 return 1;
4638
4639 case SN_ERR_INTERNAL:
4640 tv_eternity(&t->cnexpire);
4641 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4642 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4643 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02004644 if (may_dequeue_tasks(t->srv, t->proxy))
4645 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004646 return 1;
4647 }
4648 /* ensure that we have enough retries left */
willy tarreau59a6cc22006-05-12 01:29:08 +02004649 if (srv_count_retry_down(t, conn_err)) {
4650 /* let's try to offer this slot to anybody */
4651 if (may_dequeue_tasks(t->srv, t->proxy))
4652 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004653 return 1;
willy tarreau59a6cc22006-05-12 01:29:08 +02004654 }
willy tarreaudfece232006-05-02 00:19:57 +02004655 } while (t->srv == NULL || t->conn_retries > 0 || !(t->proxy->options & PR_O_REDISP));
4656
4657 /* We're on our last chance, and the REDISP option was specified.
4658 * We will ignore cookie and force to balance or use the dispatcher.
4659 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004660 /* let's try to offer this slot to anybody */
4661 if (may_dequeue_tasks(t->srv, t->proxy))
4662 task_wakeup(&rq, t->srv->queue_mgt);
4663
willy tarreaudfece232006-05-02 00:19:57 +02004664 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
4665 t->srv = NULL; /* it's left to the dispatcher to choose a server */
4666 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4667 t->flags &= ~SN_CK_MASK;
4668 t->flags |= SN_CK_DOWN;
4669 }
4670 return 0;
4671}
4672
4673/* This function performs the "redispatch" part of a connection attempt. It
4674 * will assign a server if required, queue the connection if required, and
4675 * handle errors that might arise at this level. It can change the server
4676 * state. It will return 1 if it encounters an error, switches the server
4677 * state, or has to queue a connection. Otherwise, it will return 0 indicating
4678 * that the connection is ready to use.
4679 */
4680
4681int srv_redispatch_connect(struct session *t) {
4682 int conn_err;
4683
4684 /* We know that we don't have any connection pending, so we will
4685 * try to get a new one, and wait in this state if it's queued
4686 */
4687 conn_err = assign_server_and_queue(t);
4688 switch (conn_err) {
4689 case SRV_STATUS_OK:
4690 break;
4691
4692 case SRV_STATUS_NOSRV:
willy tarreau59a6cc22006-05-12 01:29:08 +02004693 /* note: it is guaranteed that t->srv == NULL here */
willy tarreaudfece232006-05-02 00:19:57 +02004694 tv_eternity(&t->cnexpire);
4695 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
4696 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaudfece232006-05-02 00:19:57 +02004697 return 1;
4698
4699 case SRV_STATUS_QUEUED:
willy tarreau45526ed2006-05-03 20:11:50 +02004700 /* FIXME-20060503 : we should use the queue timeout instead */
4701 if (t->proxy->contimeout)
4702 tv_delayfrom(&t->cnexpire, &now, t->proxy->contimeout);
4703 else
4704 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02004705 t->srv_state = SV_STIDLE;
4706 /* do nothing else and do not wake any other session up */
4707 return 1;
4708
4709 case SRV_STATUS_FULL:
4710 case SRV_STATUS_INTERNAL:
4711 default:
4712 tv_eternity(&t->cnexpire);
4713 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4714 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4715 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02004716 if (may_dequeue_tasks(t->srv, t->proxy))
4717 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004718 return 1;
4719 }
4720 /* if we get here, it's because we got SRV_STATUS_OK, which also
4721 * means that the connection has not been queued.
4722 */
4723 return 0;
4724}
4725
4726
4727/*
willy tarreau0f7af912005-12-17 12:21:26 +01004728 * manages the server FSM and its socket. It returns 1 if a state has changed
4729 * (and a resync may be needed), 0 else.
4730 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004731int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004732 int s = t->srv_state;
4733 int c = t->cli_state;
4734 struct buffer *req = t->req;
4735 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004736 appsess *asession_temp = NULL;
4737 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004738 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004739
willy tarreau750a4722005-12-17 13:21:24 +01004740#ifdef DEBUG_FULL
4741 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4742#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004743 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4744 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4745 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4746 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004747 if (s == SV_STIDLE) {
4748 if (c == CL_STHEADERS)
4749 return 0; /* stay in idle, waiting for data to reach the client side */
4750 else if (c == CL_STCLOSE ||
4751 c == CL_STSHUTW ||
4752 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4753 tv_eternity(&t->cnexpire);
willy tarreau424e04a2006-05-13 16:08:47 +02004754 if (t->pend_pos)
4755 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreau078c79a2006-05-13 12:23:58 +02004756 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 +02004757
willy tarreau0f7af912005-12-17 12:21:26 +01004758 return 1;
4759 }
willy tarreaudfece232006-05-02 00:19:57 +02004760 else {
4761 /* Right now, we will need to create a connection to the server.
4762 * We might already have tried, and got a connection pending, in
4763 * which case we will not do anything till it's pending. It's up
4764 * to any other session to release it and wake us up again.
4765 */
willy tarreau45526ed2006-05-03 20:11:50 +02004766 if (t->pend_pos) {
4767 if (tv_cmp2_ms(&t->cnexpire, &now) > 0)
4768 return 0;
4769 else {
4770 /* we've been waiting too long here */
4771 tv_eternity(&t->cnexpire);
willy tarreau078c79a2006-05-13 12:23:58 +02004772 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
4773 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
willy tarreau45526ed2006-05-03 20:11:50 +02004774 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4775 return 1;
4776 }
4777 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004778
willy tarreaudfece232006-05-02 00:19:57 +02004779 do {
4780 /* first, get a connection */
4781 if (srv_redispatch_connect(t))
4782 return t->srv_state != SV_STIDLE;
4783
4784 /* try to (re-)connect to the server, and fail if we expire the
4785 * number of retries.
4786 */
willy tarreauf32f5242006-05-02 22:54:52 +02004787 if (srv_retryable_connect(t)) {
4788 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02004789 return t->srv_state != SV_STIDLE;
willy tarreauf32f5242006-05-02 22:54:52 +02004790 }
willy tarreaudfece232006-05-02 00:19:57 +02004791
4792 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004793 }
4794 }
4795 else if (s == SV_STCONN) { /* connection in progress */
4796 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004797 //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 +01004798 return 0; /* nothing changed */
4799 }
4800 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
willy tarreaudfece232006-05-02 00:19:57 +02004801 /* timeout, asynchronous connect error or first write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004802 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
willy tarreaudfece232006-05-02 00:19:57 +02004803
willy tarreau0f7af912005-12-17 12:21:26 +01004804 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004805 if (t->srv)
4806 t->srv->cur_sess--;
willy tarreaudfece232006-05-02 00:19:57 +02004807
4808 if (t->res_sw == RES_SILENT)
willy tarreaub1285d52005-12-18 01:20:14 +01004809 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4810 else
willy tarreaudfece232006-05-02 00:19:57 +02004811 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
willy tarreaub1285d52005-12-18 01:20:14 +01004812
willy tarreaudfece232006-05-02 00:19:57 +02004813 /* ensure that we have enough retries left */
4814 if (srv_count_retry_down(t, conn_err))
4815 return 1;
4816
4817 do {
4818 /* Now we will try to either reconnect to the same server or
4819 * connect to another server. If the connection gets queued
4820 * because all servers are saturated, then we will go back to
4821 * the SV_STIDLE state.
4822 */
willy tarreauf32f5242006-05-02 22:54:52 +02004823 if (srv_retryable_connect(t)) {
4824 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02004825 return t->srv_state != SV_STCONN;
willy tarreauf32f5242006-05-02 22:54:52 +02004826 }
willy tarreaudfece232006-05-02 00:19:57 +02004827
4828 /* we need to redispatch the connection to another server */
4829 if (srv_redispatch_connect(t))
4830 return t->srv_state != SV_STCONN;
4831 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004832 }
4833 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004834 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004835
willy tarreau0f7af912005-12-17 12:21:26 +01004836 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004837 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004838 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004839 tv_eternity(&t->swexpire);
4840 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004841 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004842 if (t->proxy->srvtimeout) {
4843 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004844 /* FIXME: to prevent the server from expiring read timeouts during writes,
4845 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004846 t->srexpire = t->swexpire;
4847 }
4848 else
4849 tv_eternity(&t->swexpire);
4850 }
willy tarreau0f7af912005-12-17 12:21:26 +01004851
4852 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4853 FD_SET(t->srv_fd, StaticReadEvent);
4854 if (t->proxy->srvtimeout)
4855 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4856 else
4857 tv_eternity(&t->srexpire);
4858
4859 t->srv_state = SV_STDATA;
willy tarreau14b4d432006-04-07 18:23:29 +02004860 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004861 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004862
4863 /* if the user wants to log as soon as possible, without counting
4864 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004865 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004866 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4867 sess_log(t);
4868 }
willy tarreau0f7af912005-12-17 12:21:26 +01004869 }
willy tarreauef900ab2005-12-17 12:52:52 +01004870 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004871 t->srv_state = SV_STHEADERS;
willy tarreau14b4d432006-04-07 18:23:29 +02004872 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004873 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4874 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004875 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004876 return 1;
4877 }
4878 }
4879 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004880 /* now parse the partial (or complete) headers */
4881 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4882 char *ptr;
4883 int delete_header;
4884
4885 ptr = rep->lr;
4886
4887 /* look for the end of the current header */
4888 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4889 ptr++;
4890
4891 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004892 int line, len;
4893
4894 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004895
4896 /* first, we'll block if security checks have caught nasty things */
4897 if (t->flags & SN_CACHEABLE) {
4898 if ((t->flags & SN_CACHE_COOK) &&
4899 (t->flags & SN_SCK_ANY) &&
4900 (t->proxy->options & PR_O_CHK_CACHE)) {
4901
4902 /* we're in presence of a cacheable response containing
4903 * a set-cookie header. We'll block it as requested by
4904 * the 'checkcache' option, and send an alert.
4905 */
4906 tv_eternity(&t->srexpire);
4907 tv_eternity(&t->swexpire);
4908 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004909 if (t->srv)
4910 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01004911 t->srv_state = SV_STCLOSE;
4912 t->logs.status = 502;
4913 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4914 if (!(t->flags & SN_ERR_MASK))
4915 t->flags |= SN_ERR_PRXCOND;
4916 if (!(t->flags & SN_FINST_MASK))
4917 t->flags |= SN_FINST_H;
4918
4919 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4920 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4921
willy tarreaudfece232006-05-02 00:19:57 +02004922 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02004923 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02004924 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004925 if (may_dequeue_tasks(t->srv, t->proxy))
4926 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004927
willy tarreau97f58572005-12-18 00:53:44 +01004928 return 1;
4929 }
4930 }
4931
willy tarreau982249e2005-12-18 00:57:06 +01004932 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4933 if (t->flags & SN_SVDENY) {
4934 tv_eternity(&t->srexpire);
4935 tv_eternity(&t->swexpire);
4936 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004937 if (t->srv)
4938 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01004939 t->srv_state = SV_STCLOSE;
4940 t->logs.status = 502;
4941 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4942 if (!(t->flags & SN_ERR_MASK))
4943 t->flags |= SN_ERR_PRXCOND;
4944 if (!(t->flags & SN_FINST_MASK))
4945 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02004946 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02004947 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02004948 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004949 if (may_dequeue_tasks(t->srv, t->proxy))
4950 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004951
willy tarreau982249e2005-12-18 00:57:06 +01004952 return 1;
4953 }
4954
willy tarreau5cbea6f2005-12-17 12:48:26 +01004955 /* we'll have something else to do here : add new headers ... */
4956
willy tarreaucd878942005-12-17 13:27:43 +01004957 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4958 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004959 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004960 * insert a set-cookie here, except if we want to insert only on POST
willy tarreau4f7a1012006-05-09 23:32:26 +02004961 * requests and this one isn't. Note that servers which don't have cookies
4962 * (eg: some backup servers) will return a full cookie removal request.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004963 */
willy tarreau750a4722005-12-17 13:21:24 +01004964 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004965 t->proxy->cookie_name,
willy tarreau4f7a1012006-05-09 23:32:26 +02004966 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
willy tarreau750a4722005-12-17 13:21:24 +01004967
willy tarreau036e1ce2005-12-17 13:46:33 +01004968 t->flags |= SN_SCK_INSERTED;
4969
willy tarreau750a4722005-12-17 13:21:24 +01004970 /* Here, we will tell an eventual cache on the client side that we don't
4971 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4972 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4973 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4974 */
willy tarreau240afa62005-12-17 13:14:35 +01004975 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004976 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4977 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004978
4979 if (rep->data + rep->l < rep->h)
4980 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4981 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004982 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004983 }
4984
4985 /* headers to be added */
4986 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004987 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4988 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004989 }
4990
willy tarreau25c4ea52005-12-18 00:49:49 +01004991 /* add a "connection: close" line if needed */
4992 if (t->proxy->options & PR_O_HTTP_CLOSE)
4993 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4994
willy tarreau5cbea6f2005-12-17 12:48:26 +01004995 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004996 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004997 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004998
Willy TARREAU767ba712006-03-01 22:40:50 +01004999 /* client connection already closed or option 'httpclose' required :
5000 * we close the server's outgoing connection right now.
5001 */
5002 if ((req->l == 0) &&
5003 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
5004 FD_CLR(t->srv_fd, StaticWriteEvent);
5005 tv_eternity(&t->swexpire);
5006
5007 /* We must ensure that the read part is still alive when switching
5008 * to shutw */
5009 FD_SET(t->srv_fd, StaticReadEvent);
5010 if (t->proxy->srvtimeout)
5011 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5012
5013 shutdown(t->srv_fd, SHUT_WR);
5014 t->srv_state = SV_STSHUTW;
5015 }
5016
willy tarreau25c4ea52005-12-18 00:49:49 +01005017 /* if the user wants to log as soon as possible, without counting
5018 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005019 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005020 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
5021 t->logs.bytes = rep->h - rep->data;
5022 sess_log(t);
5023 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005024 break;
5025 }
5026
5027 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
5028 if (ptr > rep->r - 2) {
5029 /* this is a partial header, let's wait for more to come */
5030 rep->lr = ptr;
5031 break;
5032 }
5033
5034 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
5035 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
5036
5037 /* now we know that *ptr is either \r or \n,
5038 * and that there are at least 1 char after it.
5039 */
5040 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
5041 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
5042 else
5043 rep->lr = ptr + 2; /* \r\n or \n\r */
5044
5045 /*
5046 * now we know that we have a full header ; we can do whatever
5047 * we want with these pointers :
5048 * rep->h = beginning of header
5049 * ptr = end of header (first \r or \n)
5050 * rep->lr = beginning of next line (next rep->h)
5051 * rep->r = end of data (not used at this stage)
5052 */
5053
willy tarreaua1598082005-12-17 13:08:06 +01005054
willy tarreau982249e2005-12-18 00:57:06 +01005055 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01005056 t->logs.logwait &= ~LW_RESP;
5057 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01005058 switch (t->logs.status) {
5059 case 200:
5060 case 203:
5061 case 206:
5062 case 300:
5063 case 301:
5064 case 410:
5065 /* RFC2616 @13.4:
5066 * "A response received with a status code of
5067 * 200, 203, 206, 300, 301 or 410 MAY be stored
5068 * by a cache (...) unless a cache-control
5069 * directive prohibits caching."
5070 *
5071 * RFC2616 @9.5: POST method :
5072 * "Responses to this method are not cacheable,
5073 * unless the response includes appropriate
5074 * Cache-Control or Expires header fields."
5075 */
5076 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
5077 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
5078 break;
5079 default:
5080 break;
5081 }
willy tarreau4302f492005-12-18 01:00:37 +01005082 }
5083 else if (t->logs.logwait & LW_RSPHDR) {
5084 struct cap_hdr *h;
5085 int len;
5086 for (h = t->proxy->rsp_cap; h; h = h->next) {
5087 if ((h->namelen + 2 <= ptr - rep->h) &&
5088 (rep->h[h->namelen] == ':') &&
5089 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
5090
5091 if (t->rsp_cap[h->index] == NULL)
5092 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
5093
5094 len = ptr - (rep->h + h->namelen + 2);
5095 if (len > h->len)
5096 len = h->len;
5097
5098 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
5099 t->rsp_cap[h->index][len]=0;
5100 }
5101 }
5102
willy tarreaua1598082005-12-17 13:08:06 +01005103 }
5104
willy tarreau5cbea6f2005-12-17 12:48:26 +01005105 delete_header = 0;
5106
willy tarreau982249e2005-12-18 00:57:06 +01005107 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005108 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01005109 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 +01005110 max = ptr - rep->h;
5111 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01005112 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005113 trash[len++] = '\n';
5114 write(1, trash, len);
5115 }
5116
willy tarreau25c4ea52005-12-18 00:49:49 +01005117 /* remove "connection: " if needed */
5118 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
5119 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
5120 delete_header = 1;
5121 }
5122
willy tarreau5cbea6f2005-12-17 12:48:26 +01005123 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01005124 if (!delete_header && t->proxy->rsp_exp != NULL
5125 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01005126 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005127 char term;
5128
5129 term = *ptr;
5130 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01005131 exp = t->proxy->rsp_exp;
5132 do {
5133 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
5134 switch (exp->action) {
5135 case ACT_ALLOW:
5136 if (!(t->flags & SN_SVDENY))
5137 t->flags |= SN_SVALLOW;
5138 break;
5139 case ACT_REPLACE:
5140 if (!(t->flags & SN_SVDENY)) {
5141 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
5142 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
5143 }
5144 break;
5145 case ACT_REMOVE:
5146 if (!(t->flags & SN_SVDENY))
5147 delete_header = 1;
5148 break;
5149 case ACT_DENY:
5150 if (!(t->flags & SN_SVALLOW))
5151 t->flags |= SN_SVDENY;
5152 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01005153 case ACT_PASS: /* we simply don't deny this one */
5154 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005155 }
5156 break;
5157 }
willy tarreaue39cd132005-12-17 13:00:18 +01005158 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005159 *ptr = term; /* restore the string terminator */
5160 }
5161
willy tarreau97f58572005-12-18 00:53:44 +01005162 /* check for cache-control: or pragma: headers */
5163 if (!delete_header && (t->flags & SN_CACHEABLE)) {
5164 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
5165 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5166 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
5167 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01005168 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01005169 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5170 else {
5171 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01005172 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005173 t->flags &= ~SN_CACHE_COOK;
5174 }
5175 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005176 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005177 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005178 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01005179 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5180 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005181 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01005182 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01005183 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
5184 (rep->h + 25 == ptr || rep->h[25] == ',')) {
5185 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5186 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
5187 (rep->h + 21 == ptr || rep->h[21] == ',')) {
5188 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01005189 }
5190 }
5191 }
5192
willy tarreau5cbea6f2005-12-17 12:48:26 +01005193 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01005194 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01005195 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01005196 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005197 char *p1, *p2, *p3, *p4;
5198
willy tarreau97f58572005-12-18 00:53:44 +01005199 t->flags |= SN_SCK_ANY;
5200
willy tarreau5cbea6f2005-12-17 12:48:26 +01005201 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
5202
5203 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01005204 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005205 p1++;
5206
5207 if (p1 == ptr || *p1 == ';') /* end of cookie */
5208 break;
5209
5210 /* p1 is at the beginning of the cookie name */
5211 p2 = p1;
5212
5213 while (p2 < ptr && *p2 != '=' && *p2 != ';')
5214 p2++;
5215
5216 if (p2 == ptr || *p2 == ';') /* next cookie */
5217 break;
5218
5219 p3 = p2 + 1; /* skips the '=' sign */
5220 if (p3 == ptr)
5221 break;
5222
5223 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01005224 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01005225 p4++;
5226
5227 /* here, we have the cookie name between p1 and p2,
5228 * and its value between p3 and p4.
5229 * we can process it.
5230 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005231
5232 /* first, let's see if we want to capture it */
5233 if (t->proxy->capture_name != NULL &&
5234 t->logs.srv_cookie == NULL &&
5235 (p4 - p1 >= t->proxy->capture_namelen) &&
5236 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
5237 int log_len = p4 - p1;
5238
5239 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
5240 Alert("HTTP logging : out of memory.\n");
5241 }
5242
5243 if (log_len > t->proxy->capture_len)
5244 log_len = t->proxy->capture_len;
5245 memcpy(t->logs.srv_cookie, p1, log_len);
5246 t->logs.srv_cookie[log_len] = 0;
5247 }
5248
5249 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
5250 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005251 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01005252 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005253
5254 /* If the cookie is in insert mode on a known server, we'll delete
5255 * this occurrence because we'll insert another one later.
5256 * We'll delete it too if the "indirect" option is set and we're in
5257 * a direct access. */
5258 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01005259 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005260 /* this header must be deleted */
5261 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01005262 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005263 }
5264 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
5265 /* replace bytes p3->p4 with the cookie name associated
5266 * with this server since we know it.
5267 */
5268 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01005269 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005270 }
willy tarreau0174f312005-12-18 01:02:42 +01005271 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
5272 /* insert the cookie name associated with this server
5273 * before existing cookie, and insert a delimitor between them..
5274 */
5275 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
5276 p3[t->srv->cklen] = COOKIE_DELIM;
5277 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
5278 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005279 break;
5280 }
willy tarreau12350152005-12-18 01:03:27 +01005281
5282 /* first, let's see if the cookie is our appcookie*/
5283 if ((t->proxy->appsession_name != NULL) &&
5284 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
5285
5286 /* Cool... it's the right one */
5287
willy tarreaub952e1d2005-12-18 01:31:20 +01005288 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01005289 asession_temp = &local_asession;
5290
willy tarreaub952e1d2005-12-18 01:31:20 +01005291 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005292 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5293 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5294 }
5295 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
5296 asession_temp->sessid[t->proxy->appsession_len] = 0;
5297 asession_temp->serverid = NULL;
5298
5299 /* only do insert, if lookup fails */
5300 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
5301 if ((asession_temp = pool_alloc(appsess)) == NULL) {
5302 Alert("Not enought Memory process_srv():asession:calloc().\n");
5303 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
5304 return 0;
5305 }
5306 asession_temp->sessid = local_asession.sessid;
5307 asession_temp->serverid = local_asession.serverid;
5308 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01005309 }/* end if (chtbl_lookup()) */
5310 else {
willy tarreau12350152005-12-18 01:03:27 +01005311 /* free wasted memory */
5312 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01005313 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01005314
willy tarreaub952e1d2005-12-18 01:31:20 +01005315 if (asession_temp->serverid == NULL) {
5316 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005317 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5318 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5319 }
5320 asession_temp->serverid[0] = '\0';
5321 }
5322
willy tarreaub952e1d2005-12-18 01:31:20 +01005323 if (asession_temp->serverid[0] == '\0')
5324 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01005325
5326 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
5327
5328#if defined(DEBUG_HASH)
5329 print_table(&(t->proxy->htbl_proxy));
5330#endif
5331 break;
5332 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005333 else {
5334 // fprintf(stderr,"Ignoring unknown cookie : ");
5335 // write(2, p1, p2-p1);
5336 // fprintf(stderr," = ");
5337 // write(2, p3, p4-p3);
5338 // fprintf(stderr,"\n");
5339 }
5340 break; /* we don't want to loop again since there cannot be another cookie on the same line */
5341 } /* we're now at the end of the cookie value */
5342 } /* end of cookie processing */
5343
willy tarreau97f58572005-12-18 00:53:44 +01005344 /* check for any set-cookie in case we check for cacheability */
5345 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
5346 (t->proxy->options & PR_O_CHK_CACHE) &&
5347 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
5348 t->flags |= SN_SCK_ANY;
5349 }
5350
willy tarreau5cbea6f2005-12-17 12:48:26 +01005351 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01005352 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005353 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01005354
willy tarreau5cbea6f2005-12-17 12:48:26 +01005355 rep->h = rep->lr;
5356 } /* while (rep->lr < rep->r) */
5357
5358 /* end of header processing (even if incomplete) */
5359
willy tarreauef900ab2005-12-17 12:52:52 +01005360 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5361 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
5362 * full. We cannot loop here since event_srv_read will disable it only if
5363 * rep->l == rlim-data
5364 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005365 FD_SET(t->srv_fd, StaticReadEvent);
5366 if (t->proxy->srvtimeout)
5367 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5368 else
5369 tv_eternity(&t->srexpire);
5370 }
willy tarreau0f7af912005-12-17 12:21:26 +01005371
willy tarreau8337c6b2005-12-17 13:41:01 +01005372 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005373 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005374 tv_eternity(&t->srexpire);
5375 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005376 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005377 if (t->srv)
5378 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005379 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01005380 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01005381 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01005382 if (!(t->flags & SN_ERR_MASK))
5383 t->flags |= SN_ERR_SRVCL;
5384 if (!(t->flags & SN_FINST_MASK))
5385 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005386 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005387 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005388 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005389 if (may_dequeue_tasks(t->srv, t->proxy))
5390 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005391
willy tarreau0f7af912005-12-17 12:21:26 +01005392 return 1;
5393 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005394 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01005395 * since we are in header mode, if there's no space left for headers, we
5396 * won't be able to free more later, so the session will never terminate.
5397 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005398 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 +01005399 FD_CLR(t->srv_fd, StaticReadEvent);
5400 tv_eternity(&t->srexpire);
5401 shutdown(t->srv_fd, SHUT_RD);
5402 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005403 //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 +01005404 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01005405 }
5406 /* read timeout : return a 504 to the client.
5407 */
5408 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5409 tv_eternity(&t->srexpire);
5410 tv_eternity(&t->swexpire);
5411 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005412 if (t->srv)
5413 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01005414 t->srv_state = SV_STCLOSE;
5415 t->logs.status = 504;
5416 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01005417 if (!(t->flags & SN_ERR_MASK))
5418 t->flags |= SN_ERR_SRVTO;
5419 if (!(t->flags & SN_FINST_MASK))
5420 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005421 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005422 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005423 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005424 if (may_dequeue_tasks(t->srv, t->proxy))
5425 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005426
willy tarreau8337c6b2005-12-17 13:41:01 +01005427 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005428 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005429 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01005430 /* FIXME!!! here, we don't want to switch to SHUTW if the
5431 * client shuts read too early, because we may still have
5432 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01005433 * The side-effect is that if the client completely closes its
5434 * connection during SV_STHEADER, the connection to the server
5435 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01005436 */
willy tarreau036e1ce2005-12-17 13:46:33 +01005437 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005438 FD_CLR(t->srv_fd, StaticWriteEvent);
5439 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01005440
5441 /* We must ensure that the read part is still alive when switching
5442 * to shutw */
5443 FD_SET(t->srv_fd, StaticReadEvent);
5444 if (t->proxy->srvtimeout)
5445 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5446
willy tarreau0f7af912005-12-17 12:21:26 +01005447 shutdown(t->srv_fd, SHUT_WR);
5448 t->srv_state = SV_STSHUTW;
5449 return 1;
5450 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005451 /* write timeout */
5452 /* FIXME!!! here, we don't want to switch to SHUTW if the
5453 * client shuts read too early, because we may still have
5454 * some work to do on the headers.
5455 */
5456 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5457 FD_CLR(t->srv_fd, StaticWriteEvent);
5458 tv_eternity(&t->swexpire);
5459 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005460 /* We must ensure that the read part is still alive when switching
5461 * to shutw */
5462 FD_SET(t->srv_fd, StaticReadEvent);
5463 if (t->proxy->srvtimeout)
5464 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5465
5466 /* We must ensure that the read part is still alive when switching
5467 * to shutw */
5468 FD_SET(t->srv_fd, StaticReadEvent);
5469 if (t->proxy->srvtimeout)
5470 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5471
willy tarreau036e1ce2005-12-17 13:46:33 +01005472 t->srv_state = SV_STSHUTW;
5473 if (!(t->flags & SN_ERR_MASK))
5474 t->flags |= SN_ERR_SRVTO;
5475 if (!(t->flags & SN_FINST_MASK))
5476 t->flags |= SN_FINST_H;
5477 return 1;
5478 }
willy tarreau0f7af912005-12-17 12:21:26 +01005479
5480 if (req->l == 0) {
5481 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5482 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5483 tv_eternity(&t->swexpire);
5484 }
5485 }
5486 else { /* client buffer not empty */
5487 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5488 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005489 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005490 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005491 /* FIXME: to prevent the server from expiring read timeouts during writes,
5492 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005493 t->srexpire = t->swexpire;
5494 }
willy tarreau0f7af912005-12-17 12:21:26 +01005495 else
5496 tv_eternity(&t->swexpire);
5497 }
5498 }
5499
willy tarreau5cbea6f2005-12-17 12:48:26 +01005500 /* be nice with the client side which would like to send a complete header
5501 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
5502 * would read all remaining data at once ! The client should not write past rep->lr
5503 * when the server is in header state.
5504 */
5505 //return header_processed;
5506 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01005507 }
5508 else if (s == SV_STDATA) {
5509 /* read or write error */
5510 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005511 tv_eternity(&t->srexpire);
5512 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005513 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005514 if (t->srv)
5515 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005516 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005517 if (!(t->flags & SN_ERR_MASK))
5518 t->flags |= SN_ERR_SRVCL;
5519 if (!(t->flags & SN_FINST_MASK))
5520 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005521 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005522 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005523 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005524 if (may_dequeue_tasks(t->srv, t->proxy))
5525 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005526
willy tarreau0f7af912005-12-17 12:21:26 +01005527 return 1;
5528 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005529 /* last read, or end of client write */
5530 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005531 FD_CLR(t->srv_fd, StaticReadEvent);
5532 tv_eternity(&t->srexpire);
5533 shutdown(t->srv_fd, SHUT_RD);
5534 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005535 //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 +01005536 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01005537 }
5538 /* end of client read and no more data to send */
5539 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
5540 FD_CLR(t->srv_fd, StaticWriteEvent);
5541 tv_eternity(&t->swexpire);
5542 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005543 /* We must ensure that the read part is still alive when switching
5544 * to shutw */
5545 FD_SET(t->srv_fd, StaticReadEvent);
5546 if (t->proxy->srvtimeout)
5547 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5548
willy tarreaua41a8b42005-12-17 14:02:24 +01005549 t->srv_state = SV_STSHUTW;
5550 return 1;
5551 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005552 /* read timeout */
5553 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5554 FD_CLR(t->srv_fd, StaticReadEvent);
5555 tv_eternity(&t->srexpire);
5556 shutdown(t->srv_fd, SHUT_RD);
5557 t->srv_state = SV_STSHUTR;
5558 if (!(t->flags & SN_ERR_MASK))
5559 t->flags |= SN_ERR_SRVTO;
5560 if (!(t->flags & SN_FINST_MASK))
5561 t->flags |= SN_FINST_D;
5562 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005563 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005564 /* write timeout */
5565 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005566 FD_CLR(t->srv_fd, StaticWriteEvent);
5567 tv_eternity(&t->swexpire);
5568 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005569 /* We must ensure that the read part is still alive when switching
5570 * to shutw */
5571 FD_SET(t->srv_fd, StaticReadEvent);
5572 if (t->proxy->srvtimeout)
5573 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005574 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01005575 if (!(t->flags & SN_ERR_MASK))
5576 t->flags |= SN_ERR_SRVTO;
5577 if (!(t->flags & SN_FINST_MASK))
5578 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005579 return 1;
5580 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005581
5582 /* recompute request time-outs */
5583 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005584 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5585 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5586 tv_eternity(&t->swexpire);
5587 }
5588 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005589 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01005590 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5591 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005592 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005593 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005594 /* FIXME: to prevent the server from expiring read timeouts during writes,
5595 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005596 t->srexpire = t->swexpire;
5597 }
willy tarreau0f7af912005-12-17 12:21:26 +01005598 else
5599 tv_eternity(&t->swexpire);
5600 }
5601 }
5602
willy tarreaub1ff9db2005-12-17 13:51:03 +01005603 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01005604 if (rep->l == BUFSIZE) { /* no room to read more data */
5605 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5606 FD_CLR(t->srv_fd, StaticReadEvent);
5607 tv_eternity(&t->srexpire);
5608 }
5609 }
5610 else {
5611 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5612 FD_SET(t->srv_fd, StaticReadEvent);
5613 if (t->proxy->srvtimeout)
5614 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5615 else
5616 tv_eternity(&t->srexpire);
5617 }
5618 }
5619
5620 return 0; /* other cases change nothing */
5621 }
5622 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005623 if (t->res_sw == RES_ERROR) {
5624 //FD_CLR(t->srv_fd, StaticWriteEvent);
5625 tv_eternity(&t->swexpire);
5626 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005627 if (t->srv)
5628 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005629 //close(t->srv_fd);
5630 t->srv_state = SV_STCLOSE;
5631 if (!(t->flags & SN_ERR_MASK))
5632 t->flags |= SN_ERR_SRVCL;
5633 if (!(t->flags & SN_FINST_MASK))
5634 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005635 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005636 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005637 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005638 if (may_dequeue_tasks(t->srv, t->proxy))
5639 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005640
willy tarreau036e1ce2005-12-17 13:46:33 +01005641 return 1;
5642 }
5643 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005644 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005645 tv_eternity(&t->swexpire);
5646 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005647 if (t->srv)
5648 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005649 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005650 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02005651 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005652 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005653 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005654 if (may_dequeue_tasks(t->srv, t->proxy))
5655 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005656
willy tarreau0f7af912005-12-17 12:21:26 +01005657 return 1;
5658 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005659 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5660 //FD_CLR(t->srv_fd, StaticWriteEvent);
5661 tv_eternity(&t->swexpire);
5662 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005663 if (t->srv)
5664 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005665 //close(t->srv_fd);
5666 t->srv_state = SV_STCLOSE;
5667 if (!(t->flags & SN_ERR_MASK))
5668 t->flags |= SN_ERR_SRVTO;
5669 if (!(t->flags & SN_FINST_MASK))
5670 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005671 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005672 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005673 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005674 if (may_dequeue_tasks(t->srv, t->proxy))
5675 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005676
willy tarreau036e1ce2005-12-17 13:46:33 +01005677 return 1;
5678 }
willy tarreau0f7af912005-12-17 12:21:26 +01005679 else if (req->l == 0) {
5680 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5681 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5682 tv_eternity(&t->swexpire);
5683 }
5684 }
5685 else { /* buffer not empty */
5686 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5687 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005688 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005689 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005690 /* FIXME: to prevent the server from expiring read timeouts during writes,
5691 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005692 t->srexpire = t->swexpire;
5693 }
willy tarreau0f7af912005-12-17 12:21:26 +01005694 else
5695 tv_eternity(&t->swexpire);
5696 }
5697 }
5698 return 0;
5699 }
5700 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005701 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005702 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005703 tv_eternity(&t->srexpire);
5704 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005705 if (t->srv)
5706 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005707 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005708 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005709 if (!(t->flags & SN_ERR_MASK))
5710 t->flags |= SN_ERR_SRVCL;
5711 if (!(t->flags & SN_FINST_MASK))
5712 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005713 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005714 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005715 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005716 if (may_dequeue_tasks(t->srv, t->proxy))
5717 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005718
willy tarreau0f7af912005-12-17 12:21:26 +01005719 return 1;
5720 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005721 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5722 //FD_CLR(t->srv_fd, StaticReadEvent);
5723 tv_eternity(&t->srexpire);
5724 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005725 if (t->srv)
5726 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005727 //close(t->srv_fd);
5728 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02005729 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005730 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005731 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005732 if (may_dequeue_tasks(t->srv, t->proxy))
5733 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005734
willy tarreau036e1ce2005-12-17 13:46:33 +01005735 return 1;
5736 }
5737 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5738 //FD_CLR(t->srv_fd, StaticReadEvent);
5739 tv_eternity(&t->srexpire);
5740 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005741 if (t->srv)
5742 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005743 //close(t->srv_fd);
5744 t->srv_state = SV_STCLOSE;
5745 if (!(t->flags & SN_ERR_MASK))
5746 t->flags |= SN_ERR_SRVTO;
5747 if (!(t->flags & SN_FINST_MASK))
5748 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005749 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005750 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005751 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005752 if (may_dequeue_tasks(t->srv, t->proxy))
5753 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005754
willy tarreau036e1ce2005-12-17 13:46:33 +01005755 return 1;
5756 }
willy tarreau0f7af912005-12-17 12:21:26 +01005757 else if (rep->l == BUFSIZE) { /* no room to read more data */
5758 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5759 FD_CLR(t->srv_fd, StaticReadEvent);
5760 tv_eternity(&t->srexpire);
5761 }
5762 }
5763 else {
5764 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5765 FD_SET(t->srv_fd, StaticReadEvent);
5766 if (t->proxy->srvtimeout)
5767 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5768 else
5769 tv_eternity(&t->srexpire);
5770 }
5771 }
5772 return 0;
5773 }
5774 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005775 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005776 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005777 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 +01005778 write(1, trash, len);
5779 }
5780 return 0;
5781 }
5782 return 0;
5783}
5784
5785
willy tarreau5cbea6f2005-12-17 12:48:26 +01005786/* Processes the client and server jobs of a session task, then
5787 * puts it back to the wait queue in a clean state, or
5788 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005789 * the time the task accepts to wait, or TIME_ETERNITY for
5790 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005791 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005792int process_session(struct task *t) {
5793 struct session *s = t->context;
5794 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005795
willy tarreau5cbea6f2005-12-17 12:48:26 +01005796 do {
5797 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005798 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005799 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005800 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005801 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005802 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005803 } while (fsm_resync);
5804
5805 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005806 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005807 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005808
willy tarreau5cbea6f2005-12-17 12:48:26 +01005809 tv_min(&min1, &s->crexpire, &s->cwexpire);
5810 tv_min(&min2, &s->srexpire, &s->swexpire);
5811 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005812 tv_min(&t->expire, &min1, &min2);
5813
5814 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005815 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005816
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005817#ifdef DEBUG_FULL
5818 /* DEBUG code : this should never ever happen, otherwise it indicates
5819 * that a task still has something to do and will provoke a quick loop.
5820 */
5821 if (tv_remain2(&now, &t->expire) <= 0)
5822 exit(100);
5823#endif
5824
willy tarreaub952e1d2005-12-18 01:31:20 +01005825 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005826 }
5827
willy tarreau5cbea6f2005-12-17 12:48:26 +01005828 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005829 actconn--;
5830
willy tarreau982249e2005-12-18 00:57:06 +01005831 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005832 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005833 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 +01005834 write(1, trash, len);
5835 }
5836
willy tarreau750a4722005-12-17 13:21:24 +01005837 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005838 if (s->rep != NULL)
5839 s->logs.bytes = s->rep->total;
5840
willy tarreau9fe663a2005-12-17 13:02:59 +01005841 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005842 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005843 sess_log(s);
5844
willy tarreau0f7af912005-12-17 12:21:26 +01005845 /* the task MUST not be in the run queue anymore */
5846 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005847 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005848 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005849 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005850}
5851
5852
willy tarreau2812edc2006-05-04 12:09:37 +02005853/* Sets server <s> down, notifies by all available means, recounts the
5854 * remaining servers on the proxy and transfers queued sessions whenever
5855 * possible to other servers.
5856 */
5857void set_server_down(struct server *s) {
5858 struct pendconn *pc, *pc_bck, *pc_end;
5859 struct session *sess;
5860 int xferred;
5861
5862 s->state &= ~SRV_RUNNING;
5863
5864 if (s->health == s->rise) {
5865 recount_servers(s->proxy);
5866 recalc_server_map(s->proxy);
5867
5868 /* we might have sessions queued on this server and waiting for
5869 * a connection. Those which are redispatchable will be queued
5870 * to another server or to the proxy itself.
5871 */
5872 xferred = 0;
5873 FOREACH_ITEM_SAFE(pc, pc_bck, &s->pendconns, pc_end, struct pendconn *, list) {
5874 sess = pc->sess;
5875 if ((sess->proxy->options & PR_O_REDISP)) {
5876 /* The REDISP option was specified. We will ignore
5877 * cookie and force to balance or use the dispatcher.
5878 */
5879 sess->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
5880 sess->srv = NULL; /* it's left to the dispatcher to choose a server */
5881 if ((sess->flags & SN_CK_MASK) == SN_CK_VALID) {
5882 sess->flags &= ~SN_CK_MASK;
5883 sess->flags |= SN_CK_DOWN;
5884 }
5885 pendconn_free(pc);
5886 task_wakeup(&rq, sess->task);
5887 xferred++;
5888 }
5889 }
5890
5891 sprintf(trash, "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s"
5892 " %d sessions active, %d requeued, %d remaining in queue.\n",
5893 s->state & SRV_BACKUP ? "Backup " : "",
5894 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5895 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
5896 s->cur_sess, xferred, s->nbpend);
5897
willy tarreaubc2eda62006-05-04 15:16:23 +02005898 Warning("%s", trash);
5899 send_log(s->proxy, LOG_ALERT, "%s", trash);
willy tarreau2812edc2006-05-04 12:09:37 +02005900
5901 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5902 Alert("Proxy %s has no server available !\n", s->proxy->id);
5903 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5904 }
5905 }
5906 s->health = 0; /* failure */
5907}
5908
5909
willy tarreau5cbea6f2005-12-17 12:48:26 +01005910
5911/*
5912 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005913 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005914 */
5915int process_chk(struct task *t) {
5916 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005917 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005918 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005919
willy tarreauef900ab2005-12-17 12:52:52 +01005920 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005921
willy tarreau25424f82006-03-19 19:37:48 +01005922 new_chk:
5923 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005924 if (fd < 0) { /* no check currently running */
5925 //fprintf(stderr, "process_chk: 2\n");
5926 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5927 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005928 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005929 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005930
5931 /* we don't send any health-checks when the proxy is stopped or when
5932 * the server should not be checked.
5933 */
5934 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005935 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5936 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005937 task_queue(t); /* restore t to its place in the task list */
5938 return tv_remain2(&now, &t->expire);
5939 }
5940
willy tarreau5cbea6f2005-12-17 12:48:26 +01005941 /* we'll initiate a new check */
5942 s->result = 0; /* no result yet */
5943 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005944 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005945 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5946 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5947 //fprintf(stderr, "process_chk: 3\n");
5948
willy tarreaua41a8b42005-12-17 14:02:24 +01005949 /* we'll connect to the check port on the server */
5950 sa = s->addr;
5951 sa.sin_port = htons(s->check_port);
5952
willy tarreau0174f312005-12-18 01:02:42 +01005953 /* allow specific binding :
5954 * - server-specific at first
5955 * - proxy-specific next
5956 */
5957 if (s->state & SRV_BIND_SRC) {
5958 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5959 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5960 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5961 s->proxy->id, s->id);
5962 s->result = -1;
5963 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005964 }
willy tarreau0174f312005-12-18 01:02:42 +01005965 else if (s->proxy->options & PR_O_BIND_SRC) {
5966 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5967 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5968 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5969 s->proxy->id);
5970 s->result = -1;
5971 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005972 }
willy tarreau0174f312005-12-18 01:02:42 +01005973
5974 if (!s->result) {
5975 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5976 /* OK, connection in progress or established */
5977
5978 //fprintf(stderr, "process_chk: 4\n");
5979
5980 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5981 fdtab[fd].owner = t;
5982 fdtab[fd].read = &event_srv_chk_r;
5983 fdtab[fd].write = &event_srv_chk_w;
5984 fdtab[fd].state = FD_STCONN; /* connection in progress */
5985 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005986#ifdef DEBUG_FULL
5987 assert (!FD_ISSET(fd, StaticReadEvent));
5988#endif
willy tarreau0174f312005-12-18 01:02:42 +01005989 fd_insert(fd);
5990 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5991 tv_delayfrom(&t->expire, &now, s->inter);
5992 task_queue(t); /* restore t to its place in the task list */
5993 return tv_remain(&now, &t->expire);
5994 }
5995 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5996 s->result = -1; /* a real error */
5997 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005998 }
5999 }
willy tarreau08dedbe2005-12-18 01:13:48 +01006000 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006001 }
6002
6003 if (!s->result) { /* nothing done */
6004 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01006005 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6006 tv_delayfrom(&t->expire, &t->expire, s->inter);
6007 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006008 }
6009
6010 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01006011 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01006012 s->health--; /* still good */
willy tarreau2812edc2006-05-04 12:09:37 +02006013 else
6014 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006015
6016 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01006017 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01006018 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6019 tv_delayfrom(&t->expire, &t->expire, s->inter);
6020 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006021 }
6022 else {
6023 //fprintf(stderr, "process_chk: 8\n");
6024 /* there was a test running */
6025 if (s->result > 0) { /* good server detected */
6026 //fprintf(stderr, "process_chk: 9\n");
6027 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01006028 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02006029 s->state |= SRV_RUNNING;
6030
willy tarreau535ae7a2005-12-17 12:58:00 +01006031 if (s->health == s->rise) {
willy tarreaubc2eda62006-05-04 15:16:23 +02006032 int xferred;
6033
willy tarreau62084d42006-03-24 18:57:41 +01006034 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02006035 recalc_server_map(s->proxy);
willy tarreaubc2eda62006-05-04 15:16:23 +02006036
6037 /* check if we can handle some connections queued at the proxy. We
6038 * will take as many as we can handle.
6039 */
6040 for (xferred = 0; !s->maxconn || xferred < s->maxconn; xferred++) {
6041 struct session *sess;
6042 struct pendconn *p;
6043
6044 p = pendconn_from_px(s->proxy);
6045 if (!p)
6046 break;
6047 p->sess->srv = s;
6048 sess = p->sess;
6049 pendconn_free(p);
6050 task_wakeup(&rq, sess->task);
6051 }
6052
6053 sprintf(trash,
6054 "%sServer %s/%s is UP. %d active and %d backup servers online.%s"
6055 " %d sessions requeued, %d total in queue.\n",
6056 s->state & SRV_BACKUP ? "Backup " : "",
6057 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6058 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6059 xferred, s->nbpend);
6060
6061 Warning("%s", trash);
6062 send_log(s->proxy, LOG_NOTICE, "%s", trash);
willy tarreau535ae7a2005-12-17 12:58:00 +01006063 }
willy tarreauef900ab2005-12-17 12:52:52 +01006064
willy tarreaue47c8d72005-12-17 12:55:52 +01006065 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006066 }
willy tarreauef900ab2005-12-17 12:52:52 +01006067 s->curfd = -1; /* no check running anymore */
6068 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006069 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006070 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6071 tv_delayfrom(&t->expire, &t->expire, s->inter);
6072 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006073 }
6074 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
6075 //fprintf(stderr, "process_chk: 10\n");
6076 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01006077 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01006078 s->health--; /* still good */
willy tarreau2812edc2006-05-04 12:09:37 +02006079 else
6080 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006081 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01006082 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006083 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006084 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6085 tv_delayfrom(&t->expire, &t->expire, s->inter);
6086 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006087 }
6088 /* if result is 0 and there's no timeout, we have to wait again */
6089 }
6090 //fprintf(stderr, "process_chk: 11\n");
6091 s->result = 0;
6092 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006093 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01006094}
6095
6096
willy tarreau5cbea6f2005-12-17 12:48:26 +01006097
willy tarreau59a6cc22006-05-12 01:29:08 +02006098/*
6099 * Manages a server's connection queue. If woken up, will try to dequeue as
6100 * many pending sessions as possible, and wake them up. The task has nothing
6101 * else to do, so it always returns TIME_ETERNITY.
6102 */
6103int process_srv_queue(struct task *t) {
6104 struct server *s = (struct server*)t->context;
6105 struct proxy *p = s->proxy;
6106 int xferred;
6107
6108 /* First, check if we can handle some connections queued at the proxy. We
6109 * will take as many as we can handle.
6110 */
6111 for (xferred = 0; s->cur_sess + xferred < s->maxconn; xferred++) {
6112 struct session *sess;
6113
6114 sess = pendconn_get_next_sess(s, p);
6115 if (sess == NULL)
6116 break;
6117 task_wakeup(&rq, sess->task);
6118 }
6119
6120 return TIME_ETERNITY;
6121}
6122
willy tarreau0f7af912005-12-17 12:21:26 +01006123#if STATTIME > 0
6124int stats(void);
6125#endif
6126
6127/*
willy tarreau1c2ad212005-12-18 01:11:29 +01006128 * This does 4 things :
6129 * - wake up all expired tasks
6130 * - call all runnable tasks
6131 * - call maintain_proxies() to enable/disable the listeners
6132 * - return the delay till next event in ms, -1 = wait indefinitely
6133 * Note: this part should be rewritten with the O(ln(n)) scheduler.
6134 *
willy tarreau0f7af912005-12-17 12:21:26 +01006135 */
6136
willy tarreau1c2ad212005-12-18 01:11:29 +01006137int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01006138 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01006139 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006140 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01006141
willy tarreaub952e1d2005-12-18 01:31:20 +01006142 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01006143
willy tarreau1c2ad212005-12-18 01:11:29 +01006144 /* look for expired tasks and add them to the run queue.
6145 */
willy tarreau5e698ef2006-05-02 14:51:00 +02006146 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6147 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau1c2ad212005-12-18 01:11:29 +01006148 tnext = t->next;
6149 if (t->state & TASK_RUNNING)
6150 continue;
6151
willy tarreaub952e1d2005-12-18 01:31:20 +01006152 if (tv_iseternity(&t->expire))
6153 continue;
6154
willy tarreau1c2ad212005-12-18 01:11:29 +01006155 /* wakeup expired entries. It doesn't matter if they are
6156 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01006157 */
willy tarreaub952e1d2005-12-18 01:31:20 +01006158 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006159 task_wakeup(&rq, t);
6160 }
6161 else {
6162 /* first non-runnable task. Use its expiration date as an upper bound */
6163 int temp_time = tv_remain(&now, &t->expire);
6164 if (temp_time)
6165 next_time = temp_time;
6166 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006167 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006168 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006169
willy tarreau1c2ad212005-12-18 01:11:29 +01006170 /* process each task in the run queue now. Each task may be deleted
willy tarreau7feab592006-04-22 15:13:16 +02006171 * since we only use the run queue's head. Note that any task can be
6172 * woken up by any other task and it will be processed immediately
6173 * after as it will be queued on the run queue's head.
willy tarreau1c2ad212005-12-18 01:11:29 +01006174 */
willy tarreau7feab592006-04-22 15:13:16 +02006175 while ((t = rq) != NULL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006176 int temp_time;
willy tarreau7feab592006-04-22 15:13:16 +02006177
willy tarreau1c2ad212005-12-18 01:11:29 +01006178 task_sleep(&rq, t);
6179 temp_time = t->process(t);
6180 next_time = MINTIME(temp_time, next_time);
6181 }
6182
6183 /* maintain all proxies in a consistent state. This should quickly become a task */
6184 time2 = maintain_proxies();
6185 return MINTIME(time2, next_time);
6186}
6187
6188
6189#if defined(ENABLE_EPOLL)
6190
6191/*
6192 * Main epoll() loop.
6193 */
6194
6195/* does 3 actions :
6196 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6197 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6198 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6199 *
6200 * returns 0 if initialization failed, !0 otherwise.
6201 */
6202
6203int epoll_loop(int action) {
6204 int next_time;
6205 int status;
6206 int fd;
6207
6208 int fds, count;
6209 int pr, pw, sr, sw;
6210 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
6211 struct epoll_event ev;
6212
6213 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01006214 static struct epoll_event *epoll_events = NULL;
6215 static int epoll_fd;
6216
6217 if (action == POLL_LOOP_ACTION_INIT) {
6218 epoll_fd = epoll_create(global.maxsock + 1);
6219 if (epoll_fd < 0)
6220 return 0;
6221 else {
6222 epoll_events = (struct epoll_event*)
6223 calloc(1, sizeof(struct epoll_event) * global.maxsock);
6224 PrevReadEvent = (fd_set *)
6225 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6226 PrevWriteEvent = (fd_set *)
6227 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006228 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006229 return 1;
6230 }
6231 else if (action == POLL_LOOP_ACTION_CLEAN) {
6232 if (PrevWriteEvent) free(PrevWriteEvent);
6233 if (PrevReadEvent) free(PrevReadEvent);
6234 if (epoll_events) free(epoll_events);
6235 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01006236 epoll_fd = 0;
6237 return 1;
6238 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006239
willy tarreau1c2ad212005-12-18 01:11:29 +01006240 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006241
willy tarreau1c2ad212005-12-18 01:11:29 +01006242 tv_now(&now);
6243
6244 while (1) {
6245 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01006246
6247 /* stop when there's no connection left and we don't allow them anymore */
6248 if (!actconn && listeners == 0)
6249 break;
6250
willy tarreau0f7af912005-12-17 12:21:26 +01006251#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01006252 {
6253 int time2;
6254 time2 = stats();
6255 next_time = MINTIME(time2, next_time);
6256 }
willy tarreau0f7af912005-12-17 12:21:26 +01006257#endif
6258
willy tarreau1c2ad212005-12-18 01:11:29 +01006259 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6260
6261 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
6262 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
6263
6264 if ((ro^rn) | (wo^wn)) {
6265 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6266#define FDSETS_ARE_INT_ALIGNED
6267#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01006268
willy tarreauad90a0c2005-12-18 01:09:15 +01006269#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6270#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01006271 pr = (ro >> count) & 1;
6272 pw = (wo >> count) & 1;
6273 sr = (rn >> count) & 1;
6274 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01006275#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006276 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
6277 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
6278 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6279 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01006280#endif
6281#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006282 pr = FD_ISSET(fd, PrevReadEvent);
6283 pw = FD_ISSET(fd, PrevWriteEvent);
6284 sr = FD_ISSET(fd, StaticReadEvent);
6285 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01006286#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01006287 if (!((sr^pr) | (sw^pw)))
6288 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01006289
willy tarreau1c2ad212005-12-18 01:11:29 +01006290 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
6291 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01006292
willy tarreaub952e1d2005-12-18 01:31:20 +01006293#ifdef EPOLL_CTL_MOD_WORKAROUND
6294 /* I encountered a rarely reproducible problem with
6295 * EPOLL_CTL_MOD where a modified FD (systematically
6296 * the one in epoll_events[0], fd#7) would sometimes
6297 * be set EPOLL_OUT while asked for a read ! This is
6298 * with the 2.4 epoll patch. The workaround is to
6299 * delete then recreate in case of modification.
6300 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
6301 * nor RHEL kernels.
6302 */
6303
6304 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
6305 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
6306
6307 if ((sr | sw))
6308 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
6309#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006310 if ((pr | pw)) {
6311 /* the file-descriptor already exists... */
6312 if ((sr | sw)) {
6313 /* ...and it will still exist */
6314 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
6315 // perror("epoll_ctl(MOD)");
6316 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006317 }
6318 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01006319 /* ...and it will be removed */
6320 if (fdtab[fd].state != FD_STCLOSE &&
6321 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
6322 // perror("epoll_ctl(DEL)");
6323 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006324 }
6325 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006326 } else {
6327 /* the file-descriptor did not exist, let's add it */
6328 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
6329 // perror("epoll_ctl(ADD)");
6330 // exit(1);
6331 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006332 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006333#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01006334 }
6335 ((int*)PrevReadEvent)[fds] = rn;
6336 ((int*)PrevWriteEvent)[fds] = wn;
6337 }
6338 }
6339
6340 /* now let's wait for events */
6341 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
6342 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006343
willy tarreau1c2ad212005-12-18 01:11:29 +01006344 for (count = 0; count < status; count++) {
6345 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01006346
6347 if (FD_ISSET(fd, StaticReadEvent)) {
6348 if (fdtab[fd].state == FD_STCLOSE)
6349 continue;
6350 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
6351 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006352 }
willy tarreau05be12b2006-03-19 19:35:00 +01006353
6354 if (FD_ISSET(fd, StaticWriteEvent)) {
6355 if (fdtab[fd].state == FD_STCLOSE)
6356 continue;
6357 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
6358 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006359 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006360 }
6361 }
6362 return 1;
6363}
6364#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006365
willy tarreauad90a0c2005-12-18 01:09:15 +01006366
willy tarreau5cbea6f2005-12-17 12:48:26 +01006367
willy tarreau1c2ad212005-12-18 01:11:29 +01006368#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01006369
willy tarreau1c2ad212005-12-18 01:11:29 +01006370/*
6371 * Main poll() loop.
6372 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006373
willy tarreau1c2ad212005-12-18 01:11:29 +01006374/* does 3 actions :
6375 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6376 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6377 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6378 *
6379 * returns 0 if initialization failed, !0 otherwise.
6380 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006381
willy tarreau1c2ad212005-12-18 01:11:29 +01006382int poll_loop(int action) {
6383 int next_time;
6384 int status;
6385 int fd, nbfd;
6386
6387 int fds, count;
6388 int sr, sw;
6389 unsigned rn, wn; /* read new, write new */
6390
6391 /* private data */
6392 static struct pollfd *poll_events = NULL;
6393
6394 if (action == POLL_LOOP_ACTION_INIT) {
6395 poll_events = (struct pollfd*)
6396 calloc(1, sizeof(struct pollfd) * global.maxsock);
6397 return 1;
6398 }
6399 else if (action == POLL_LOOP_ACTION_CLEAN) {
6400 if (poll_events)
6401 free(poll_events);
6402 return 1;
6403 }
6404
6405 /* OK, it's POLL_LOOP_ACTION_RUN */
6406
6407 tv_now(&now);
6408
6409 while (1) {
6410 next_time = process_runnable_tasks();
6411
6412 /* stop when there's no connection left and we don't allow them anymore */
6413 if (!actconn && listeners == 0)
6414 break;
6415
6416#if STATTIME > 0
6417 {
6418 int time2;
6419 time2 = stats();
6420 next_time = MINTIME(time2, next_time);
6421 }
6422#endif
6423
6424
6425 nbfd = 0;
6426 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6427
6428 rn = ((int*)StaticReadEvent)[fds];
6429 wn = ((int*)StaticWriteEvent)[fds];
6430
6431 if ((rn|wn)) {
6432 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6433#define FDSETS_ARE_INT_ALIGNED
6434#ifdef FDSETS_ARE_INT_ALIGNED
6435
6436#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6437#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6438 sr = (rn >> count) & 1;
6439 sw = (wn >> count) & 1;
6440#else
6441 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6442 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
6443#endif
6444#else
6445 sr = FD_ISSET(fd, StaticReadEvent);
6446 sw = FD_ISSET(fd, StaticWriteEvent);
6447#endif
6448 if ((sr|sw)) {
6449 poll_events[nbfd].fd = fd;
6450 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
6451 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01006452 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006453 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006454 }
6455 }
6456
6457 /* now let's wait for events */
6458 status = poll(poll_events, nbfd, next_time);
6459 tv_now(&now);
6460
6461 for (count = 0; status > 0 && count < nbfd; count++) {
6462 fd = poll_events[count].fd;
6463
6464 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
6465 continue;
6466
6467 /* ok, we found one active fd */
6468 status--;
6469
willy tarreau05be12b2006-03-19 19:35:00 +01006470 if (FD_ISSET(fd, StaticReadEvent)) {
6471 if (fdtab[fd].state == FD_STCLOSE)
6472 continue;
6473 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
6474 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006475 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006476
willy tarreau05be12b2006-03-19 19:35:00 +01006477 if (FD_ISSET(fd, StaticWriteEvent)) {
6478 if (fdtab[fd].state == FD_STCLOSE)
6479 continue;
6480 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
6481 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006482 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006483 }
6484 }
6485 return 1;
6486}
willy tarreauad90a0c2005-12-18 01:09:15 +01006487#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006488
willy tarreauad90a0c2005-12-18 01:09:15 +01006489
willy tarreauad90a0c2005-12-18 01:09:15 +01006490
willy tarreau1c2ad212005-12-18 01:11:29 +01006491/*
6492 * Main select() loop.
6493 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006494
willy tarreau1c2ad212005-12-18 01:11:29 +01006495/* does 3 actions :
6496 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6497 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6498 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6499 *
6500 * returns 0 if initialization failed, !0 otherwise.
6501 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006502
willy tarreauad90a0c2005-12-18 01:09:15 +01006503
willy tarreau1c2ad212005-12-18 01:11:29 +01006504int select_loop(int action) {
6505 int next_time;
6506 int status;
6507 int fd,i;
6508 struct timeval delta;
6509 int readnotnull, writenotnull;
6510 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01006511
willy tarreau1c2ad212005-12-18 01:11:29 +01006512 if (action == POLL_LOOP_ACTION_INIT) {
6513 ReadEvent = (fd_set *)
6514 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6515 WriteEvent = (fd_set *)
6516 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6517 return 1;
6518 }
6519 else if (action == POLL_LOOP_ACTION_CLEAN) {
6520 if (WriteEvent) free(WriteEvent);
6521 if (ReadEvent) free(ReadEvent);
6522 return 1;
6523 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006524
willy tarreau1c2ad212005-12-18 01:11:29 +01006525 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01006526
willy tarreau1c2ad212005-12-18 01:11:29 +01006527 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006528
willy tarreau1c2ad212005-12-18 01:11:29 +01006529 while (1) {
6530 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01006531
willy tarreau1c2ad212005-12-18 01:11:29 +01006532 /* stop when there's no connection left and we don't allow them anymore */
6533 if (!actconn && listeners == 0)
6534 break;
6535
6536#if STATTIME > 0
6537 {
6538 int time2;
6539 time2 = stats();
6540 next_time = MINTIME(time2, next_time);
6541 }
6542#endif
6543
willy tarreau1c2ad212005-12-18 01:11:29 +01006544 if (next_time > 0) { /* FIXME */
6545 /* Convert to timeval */
6546 /* to avoid eventual select loops due to timer precision */
6547 next_time += SCHEDULER_RESOLUTION;
6548 delta.tv_sec = next_time / 1000;
6549 delta.tv_usec = (next_time % 1000) * 1000;
6550 }
6551 else if (next_time == 0) { /* allow select to return immediately when needed */
6552 delta.tv_sec = delta.tv_usec = 0;
6553 }
6554
6555
6556 /* let's restore fdset state */
6557
6558 readnotnull = 0; writenotnull = 0;
6559 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
6560 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
6561 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
6562 }
6563
6564 // /* just a verification code, needs to be removed for performance */
6565 // for (i=0; i<maxfd; i++) {
6566 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
6567 // abort();
6568 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
6569 // abort();
6570 //
6571 // }
6572
6573 status = select(maxfd,
6574 readnotnull ? ReadEvent : NULL,
6575 writenotnull ? WriteEvent : NULL,
6576 NULL,
6577 (next_time >= 0) ? &delta : NULL);
6578
6579 /* this is an experiment on the separation of the select work */
6580 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6581 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6582
6583 tv_now(&now);
6584
6585 if (status > 0) { /* must proceed with events */
6586
6587 int fds;
6588 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01006589
willy tarreau1c2ad212005-12-18 01:11:29 +01006590 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
6591 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
6592 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
6593
6594 /* if we specify read first, the accepts and zero reads will be
6595 * seen first. Moreover, system buffers will be flushed faster.
6596 */
willy tarreau05be12b2006-03-19 19:35:00 +01006597 if (FD_ISSET(fd, ReadEvent)) {
6598 if (fdtab[fd].state == FD_STCLOSE)
6599 continue;
6600 fdtab[fd].read(fd);
6601 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006602
willy tarreau05be12b2006-03-19 19:35:00 +01006603 if (FD_ISSET(fd, WriteEvent)) {
6604 if (fdtab[fd].state == FD_STCLOSE)
6605 continue;
6606 fdtab[fd].write(fd);
6607 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006608 }
6609 }
6610 else {
6611 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01006612 }
willy tarreau0f7af912005-12-17 12:21:26 +01006613 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006614 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006615}
6616
6617
6618#if STATTIME > 0
6619/*
6620 * Display proxy statistics regularly. It is designed to be called from the
6621 * select_loop().
6622 */
6623int stats(void) {
6624 static int lines;
6625 static struct timeval nextevt;
6626 static struct timeval lastevt;
6627 static struct timeval starttime = {0,0};
6628 unsigned long totaltime, deltatime;
6629 int ret;
6630
willy tarreau750a4722005-12-17 13:21:24 +01006631 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01006632 deltatime = (tv_diff(&lastevt, &now)?:1);
6633 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01006634
willy tarreau9fe663a2005-12-17 13:02:59 +01006635 if (global.mode & MODE_STATS) {
6636 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006637 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01006638 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
6639 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006640 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01006641 actconn, totalconn,
6642 stats_tsk_new, stats_tsk_good,
6643 stats_tsk_left, stats_tsk_right,
6644 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
6645 }
6646 }
6647
6648 tv_delayfrom(&nextevt, &now, STATTIME);
6649
6650 lastevt=now;
6651 }
6652 ret = tv_remain(&now, &nextevt);
6653 return ret;
6654}
6655#endif
6656
6657
6658/*
6659 * this function enables proxies when there are enough free sessions,
6660 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01006661 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01006662 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01006663 */
6664static int maintain_proxies(void) {
6665 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01006666 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006667 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01006668
6669 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01006670 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01006671
6672 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01006673 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01006674 while (p) {
6675 if (p->nbconn < p->maxconn) {
6676 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006677 for (l = p->listen; l != NULL; l = l->next) {
6678 FD_SET(l->fd, StaticReadEvent);
6679 }
willy tarreau0f7af912005-12-17 12:21:26 +01006680 p->state = PR_STRUN;
6681 }
6682 }
6683 else {
6684 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006685 for (l = p->listen; l != NULL; l = l->next) {
6686 FD_CLR(l->fd, StaticReadEvent);
6687 }
willy tarreau0f7af912005-12-17 12:21:26 +01006688 p->state = PR_STIDLE;
6689 }
6690 }
6691 p = p->next;
6692 }
6693 }
6694 else { /* block all proxies */
6695 while (p) {
6696 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006697 for (l = p->listen; l != NULL; l = l->next) {
6698 FD_CLR(l->fd, StaticReadEvent);
6699 }
willy tarreau0f7af912005-12-17 12:21:26 +01006700 p->state = PR_STIDLE;
6701 }
6702 p = p->next;
6703 }
6704 }
6705
willy tarreau5cbea6f2005-12-17 12:48:26 +01006706 if (stopping) {
6707 p = proxy;
6708 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01006709 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006710 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006711 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006712 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006713 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006714 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006715
willy tarreaua41a8b42005-12-17 14:02:24 +01006716 for (l = p->listen; l != NULL; l = l->next) {
6717 fd_delete(l->fd);
6718 listeners--;
6719 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006720 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006721 }
6722 else {
6723 tleft = MINTIME(t, tleft);
6724 }
6725 }
6726 p = p->next;
6727 }
6728 }
6729 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006730}
6731
6732/*
6733 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006734 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6735 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006736 */
6737static void soft_stop(void) {
6738 struct proxy *p;
6739
6740 stopping = 1;
6741 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006742 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006743 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006744 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006745 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006746 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006747 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006748 }
willy tarreau0f7af912005-12-17 12:21:26 +01006749 p = p->next;
6750 }
6751}
6752
willy tarreaudbd3bef2006-01-20 19:35:18 +01006753static void pause_proxy(struct proxy *p) {
6754 struct listener *l;
6755 for (l = p->listen; l != NULL; l = l->next) {
Willy TARREAU007aa462006-05-14 09:55:23 +02006756 if (shutdown(l->fd, SHUT_RD) == 0) {
6757 FD_CLR(l->fd, StaticReadEvent);
6758 p->state = PR_STPAUSED;
6759 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006760 }
6761}
6762
6763/*
6764 * This function temporarily disables listening so that another new instance
6765 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006766 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006767 * the proxy, or a SIGTTIN can be sent to listen again.
6768 */
6769static void pause_proxies(void) {
Willy TARREAU007aa462006-05-14 09:55:23 +02006770 int err;
willy tarreaudbd3bef2006-01-20 19:35:18 +01006771 struct proxy *p;
6772
Willy TARREAU007aa462006-05-14 09:55:23 +02006773 err = 0;
willy tarreaudbd3bef2006-01-20 19:35:18 +01006774 p = proxy;
6775 tv_now(&now); /* else, the old time before select will be used */
6776 while (p) {
6777 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6778 Warning("Pausing proxy %s.\n", p->id);
6779 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6780 pause_proxy(p);
Willy TARREAU007aa462006-05-14 09:55:23 +02006781 if (p->state != PR_STPAUSED) {
6782 err |= 1;
6783 Warning("Proxy %s failed to enter pause mode.\n", p->id);
6784 send_log(p, LOG_WARNING, "Proxy %s failed to enter pause mode.\n", p->id);
6785 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006786 }
6787 p = p->next;
6788 }
Willy TARREAU007aa462006-05-14 09:55:23 +02006789 if (err) {
6790 Warning("Some proxies refused to pause, performing soft stop now.\n");
6791 send_log(p, LOG_WARNING, "Some proxies refused to pause, performing soft stop now.\n");
6792 soft_stop();
6793 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006794}
6795
6796
6797/*
6798 * This function reactivates listening. This can be used after a call to
6799 * sig_pause(), for example when a new instance has failed starting up.
6800 * It is designed to be called upon reception of a SIGTTIN.
6801 */
6802static void listen_proxies(void) {
6803 struct proxy *p;
6804 struct listener *l;
6805
6806 p = proxy;
6807 tv_now(&now); /* else, the old time before select will be used */
6808 while (p) {
6809 if (p->state == PR_STPAUSED) {
6810 Warning("Enabling proxy %s.\n", p->id);
6811 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6812
6813 for (l = p->listen; l != NULL; l = l->next) {
6814 if (listen(l->fd, p->maxconn) == 0) {
6815 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6816 FD_SET(l->fd, StaticReadEvent);
6817 p->state = PR_STRUN;
6818 }
6819 else
6820 p->state = PR_STIDLE;
6821 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006822 int port;
6823
6824 if (l->addr.ss_family == AF_INET6)
6825 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6826 else
6827 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6828
willy tarreaudbd3bef2006-01-20 19:35:18 +01006829 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006830 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006831 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006832 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006833 /* Another port might have been enabled. Let's stop everything. */
6834 pause_proxy(p);
6835 break;
6836 }
6837 }
6838 }
6839 p = p->next;
6840 }
6841}
6842
6843
willy tarreau0f7af912005-12-17 12:21:26 +01006844/*
6845 * upon SIGUSR1, let's have a soft stop.
6846 */
6847void sig_soft_stop(int sig) {
6848 soft_stop();
6849 signal(sig, SIG_IGN);
6850}
6851
willy tarreaudbd3bef2006-01-20 19:35:18 +01006852/*
6853 * upon SIGTTOU, we pause everything
6854 */
6855void sig_pause(int sig) {
6856 pause_proxies();
6857 signal(sig, sig_pause);
6858}
willy tarreau0f7af912005-12-17 12:21:26 +01006859
willy tarreau8337c6b2005-12-17 13:41:01 +01006860/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006861 * upon SIGTTIN, let's have a soft stop.
6862 */
6863void sig_listen(int sig) {
6864 listen_proxies();
6865 signal(sig, sig_listen);
6866}
6867
6868/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006869 * this function dumps every server's state when the process receives SIGHUP.
6870 */
6871void sig_dump_state(int sig) {
6872 struct proxy *p = proxy;
6873
6874 Warning("SIGHUP received, dumping servers states.\n");
6875 while (p) {
6876 struct server *s = p->srv;
6877
willy tarreau4632c212006-05-02 23:32:51 +02006878 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006879 while (s) {
willy tarreau4632c212006-05-02 23:32:51 +02006880 snprintf(trash, sizeof(trash),
6881 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %d tot.",
6882 p->id, s->id,
6883 (s->state & SRV_RUNNING) ? "UP" : "DOWN",
6884 s->cur_sess, s->nbpend, s->cum_sess);
willy tarreau14b4d432006-04-07 18:23:29 +02006885 Warning("%s\n", trash);
6886 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01006887 s = s->next;
6888 }
willy tarreaudd07e972005-12-18 00:48:48 +01006889
willy tarreau62084d42006-03-24 18:57:41 +01006890 if (p->srv_act == 0) {
willy tarreau4632c212006-05-02 23:32:51 +02006891 snprintf(trash, sizeof(trash),
6892 "SIGHUP: Proxy %s %s ! Conn: %d act, %d pend (%d unass), %d tot.",
6893 p->id,
6894 (p->srv_bck) ? "is running on backup servers" : "has no server available",
6895 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02006896 } else {
6897 snprintf(trash, sizeof(trash),
willy tarreau4632c212006-05-02 23:32:51 +02006898 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
6899 " Conn: %d act, %d pend (%d unass), %d tot.",
6900 p->id, p->srv_act, p->srv_bck,
6901 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02006902 }
6903 Warning("%s\n", trash);
6904 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01006905
willy tarreau8337c6b2005-12-17 13:41:01 +01006906 p = p->next;
6907 }
6908 signal(sig, sig_dump_state);
6909}
6910
willy tarreau0f7af912005-12-17 12:21:26 +01006911void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006912 struct task *t, *tnext;
6913 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006914
willy tarreau5e698ef2006-05-02 14:51:00 +02006915 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6916 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006917 tnext = t->next;
6918 s = t->context;
6919 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6920 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6921 "req=%d, rep=%d, clifd=%d\n",
6922 s, tv_remain(&now, &t->expire),
6923 s->cli_state,
6924 s->srv_state,
6925 FD_ISSET(s->cli_fd, StaticReadEvent),
6926 FD_ISSET(s->cli_fd, StaticWriteEvent),
6927 FD_ISSET(s->srv_fd, StaticReadEvent),
6928 FD_ISSET(s->srv_fd, StaticWriteEvent),
6929 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6930 );
willy tarreau0f7af912005-12-17 12:21:26 +01006931 }
willy tarreau12350152005-12-18 01:03:27 +01006932}
6933
willy tarreau64a3cc32005-12-18 01:13:11 +01006934#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006935static void fast_stop(void)
6936{
6937 struct proxy *p;
6938 p = proxy;
6939 while (p) {
6940 p->grace = 0;
6941 p = p->next;
6942 }
6943 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006944}
6945
willy tarreau12350152005-12-18 01:03:27 +01006946void sig_int(int sig) {
6947 /* This would normally be a hard stop,
6948 but we want to be sure about deallocation,
6949 and so on, so we do a soft stop with
6950 0 GRACE time
6951 */
6952 fast_stop();
6953 /* If we are killed twice, we decide to die*/
6954 signal(sig, SIG_DFL);
6955}
6956
6957void sig_term(int sig) {
6958 /* This would normally be a hard stop,
6959 but we want to be sure about deallocation,
6960 and so on, so we do a soft stop with
6961 0 GRACE time
6962 */
6963 fast_stop();
6964 /* If we are killed twice, we decide to die*/
6965 signal(sig, SIG_DFL);
6966}
willy tarreau64a3cc32005-12-18 01:13:11 +01006967#endif
willy tarreau12350152005-12-18 01:03:27 +01006968
willy tarreauc1f47532005-12-18 01:08:26 +01006969/* returns the pointer to an error in the replacement string, or NULL if OK */
6970char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006971 struct hdr_exp *exp;
6972
willy tarreauc1f47532005-12-18 01:08:26 +01006973 if (replace != NULL) {
6974 char *err;
6975 err = check_replace_string(replace);
6976 if (err)
6977 return err;
6978 }
6979
willy tarreaue39cd132005-12-17 13:00:18 +01006980 while (*head != NULL)
6981 head = &(*head)->next;
6982
6983 exp = calloc(1, sizeof(struct hdr_exp));
6984
6985 exp->preg = preg;
6986 exp->replace = replace;
6987 exp->action = action;
6988 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006989
6990 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006991}
6992
willy tarreau9fe663a2005-12-17 13:02:59 +01006993
willy tarreau0f7af912005-12-17 12:21:26 +01006994/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006995 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006996 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006997int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006998
willy tarreau9fe663a2005-12-17 13:02:59 +01006999 if (!strcmp(args[0], "global")) { /* new section */
7000 /* no option, nothing special to do */
7001 return 0;
7002 }
7003 else if (!strcmp(args[0], "daemon")) {
7004 global.mode |= MODE_DAEMON;
7005 }
7006 else if (!strcmp(args[0], "debug")) {
7007 global.mode |= MODE_DEBUG;
7008 }
willy tarreau64a3cc32005-12-18 01:13:11 +01007009 else if (!strcmp(args[0], "noepoll")) {
7010 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
7011 }
7012 else if (!strcmp(args[0], "nopoll")) {
7013 cfg_polling_mechanism &= ~POLL_USE_POLL;
7014 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007015 else if (!strcmp(args[0], "quiet")) {
7016 global.mode |= MODE_QUIET;
7017 }
7018 else if (!strcmp(args[0], "stats")) {
7019 global.mode |= MODE_STATS;
7020 }
7021 else if (!strcmp(args[0], "uid")) {
7022 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007023 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007024 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007025 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007026 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007027 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007028 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007029 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007030 global.uid = atol(args[1]);
7031 }
7032 else if (!strcmp(args[0], "gid")) {
7033 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007034 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007035 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007036 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007037 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007038 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007039 return -1;
7040 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007041 global.gid = atol(args[1]);
7042 }
7043 else if (!strcmp(args[0], "nbproc")) {
7044 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007045 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007046 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007047 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007048 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007049 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007050 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007051 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007052 global.nbproc = atol(args[1]);
7053 }
7054 else if (!strcmp(args[0], "maxconn")) {
7055 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007056 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007057 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007058 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007059 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007060 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007061 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007062 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007063 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01007064#ifdef SYSTEM_MAXCONN
7065 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
7066 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);
7067 global.maxconn = DEFAULT_MAXCONN;
7068 }
7069#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01007070 }
willy tarreaub1285d52005-12-18 01:20:14 +01007071 else if (!strcmp(args[0], "ulimit-n")) {
7072 if (global.rlimit_nofile != 0) {
7073 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7074 return 0;
7075 }
7076 if (*(args[1]) == 0) {
7077 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
7078 return -1;
7079 }
7080 global.rlimit_nofile = atol(args[1]);
7081 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007082 else if (!strcmp(args[0], "chroot")) {
7083 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007084 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007085 return 0;
7086 }
7087 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007088 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007089 return -1;
7090 }
7091 global.chroot = strdup(args[1]);
7092 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007093 else if (!strcmp(args[0], "pidfile")) {
7094 if (global.pidfile != NULL) {
7095 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7096 return 0;
7097 }
7098 if (*(args[1]) == 0) {
7099 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
7100 return -1;
7101 }
7102 global.pidfile = strdup(args[1]);
7103 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007104 else if (!strcmp(args[0], "log")) { /* syslog server address */
7105 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01007106 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007107
7108 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007109 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007110 return -1;
7111 }
7112
7113 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7114 if (!strcmp(log_facilities[facility], args[2]))
7115 break;
7116
7117 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007118 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007119 exit(1);
7120 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007121
7122 level = 7; /* max syslog level = debug */
7123 if (*(args[3])) {
7124 while (level >= 0 && strcmp(log_levels[level], args[3]))
7125 level--;
7126 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007127 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007128 exit(1);
7129 }
7130 }
7131
willy tarreau9fe663a2005-12-17 13:02:59 +01007132 sa = str2sa(args[1]);
7133 if (!sa->sin_port)
7134 sa->sin_port = htons(SYSLOG_PORT);
7135
7136 if (global.logfac1 == -1) {
7137 global.logsrv1 = *sa;
7138 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007139 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007140 }
7141 else if (global.logfac2 == -1) {
7142 global.logsrv2 = *sa;
7143 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007144 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007145 }
7146 else {
7147 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
7148 return -1;
7149 }
7150
7151 }
7152 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007153 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01007154 return -1;
7155 }
7156 return 0;
7157}
7158
7159
willy tarreaua41a8b42005-12-17 14:02:24 +01007160void init_default_instance() {
7161 memset(&defproxy, 0, sizeof(defproxy));
7162 defproxy.mode = PR_MODE_TCP;
7163 defproxy.state = PR_STNEW;
7164 defproxy.maxconn = cfg_maxpconn;
7165 defproxy.conn_retries = CONN_RETRIES;
7166 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
7167}
7168
willy tarreau9fe663a2005-12-17 13:02:59 +01007169/*
7170 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
7171 */
7172int cfg_parse_listen(char *file, int linenum, char **args) {
7173 static struct proxy *curproxy = NULL;
7174 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01007175 char *err;
willy tarreau12350152005-12-18 01:03:27 +01007176 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01007177
7178 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01007179 if (!*args[1]) {
7180 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
7181 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007182 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007183 return -1;
7184 }
7185
7186 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007187 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007188 return -1;
7189 }
willy tarreaudfece232006-05-02 00:19:57 +02007190
willy tarreau9fe663a2005-12-17 13:02:59 +01007191 curproxy->next = proxy;
7192 proxy = curproxy;
willy tarreaudfece232006-05-02 00:19:57 +02007193 LIST_INIT(&curproxy->pendconns);
7194
willy tarreau9fe663a2005-12-17 13:02:59 +01007195 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01007196
7197 /* parse the listener address if any */
7198 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007199 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007200 if (!curproxy->listen)
7201 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007202 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01007203 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007204
willy tarreau9fe663a2005-12-17 13:02:59 +01007205 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01007206 curproxy->state = defproxy.state;
7207 curproxy->maxconn = defproxy.maxconn;
7208 curproxy->conn_retries = defproxy.conn_retries;
7209 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007210
7211 if (defproxy.check_req)
7212 curproxy->check_req = strdup(defproxy.check_req);
7213 curproxy->check_len = defproxy.check_len;
7214
7215 if (defproxy.cookie_name)
7216 curproxy->cookie_name = strdup(defproxy.cookie_name);
7217 curproxy->cookie_len = defproxy.cookie_len;
7218
7219 if (defproxy.capture_name)
7220 curproxy->capture_name = strdup(defproxy.capture_name);
7221 curproxy->capture_namelen = defproxy.capture_namelen;
7222 curproxy->capture_len = defproxy.capture_len;
7223
7224 if (defproxy.errmsg.msg400)
7225 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
7226 curproxy->errmsg.len400 = defproxy.errmsg.len400;
7227
7228 if (defproxy.errmsg.msg403)
7229 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
7230 curproxy->errmsg.len403 = defproxy.errmsg.len403;
7231
7232 if (defproxy.errmsg.msg408)
7233 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
7234 curproxy->errmsg.len408 = defproxy.errmsg.len408;
7235
7236 if (defproxy.errmsg.msg500)
7237 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
7238 curproxy->errmsg.len500 = defproxy.errmsg.len500;
7239
7240 if (defproxy.errmsg.msg502)
7241 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
7242 curproxy->errmsg.len502 = defproxy.errmsg.len502;
7243
7244 if (defproxy.errmsg.msg503)
7245 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
7246 curproxy->errmsg.len503 = defproxy.errmsg.len503;
7247
7248 if (defproxy.errmsg.msg504)
7249 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
7250 curproxy->errmsg.len504 = defproxy.errmsg.len504;
7251
willy tarreaua41a8b42005-12-17 14:02:24 +01007252 curproxy->clitimeout = defproxy.clitimeout;
7253 curproxy->contimeout = defproxy.contimeout;
7254 curproxy->srvtimeout = defproxy.srvtimeout;
7255 curproxy->mode = defproxy.mode;
7256 curproxy->logfac1 = defproxy.logfac1;
7257 curproxy->logsrv1 = defproxy.logsrv1;
7258 curproxy->loglev1 = defproxy.loglev1;
7259 curproxy->logfac2 = defproxy.logfac2;
7260 curproxy->logsrv2 = defproxy.logsrv2;
7261 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01007262 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01007263 curproxy->grace = defproxy.grace;
7264 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01007265 curproxy->mon_net = defproxy.mon_net;
7266 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01007267 return 0;
7268 }
7269 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007270 /* some variables may have already been initialized earlier */
7271 if (defproxy.check_req) free(defproxy.check_req);
7272 if (defproxy.cookie_name) free(defproxy.cookie_name);
7273 if (defproxy.capture_name) free(defproxy.capture_name);
7274 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
7275 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
7276 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
7277 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
7278 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
7279 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
7280 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
7281
7282 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01007283 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01007284 return 0;
7285 }
7286 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007287 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007288 return -1;
7289 }
7290
willy tarreaua41a8b42005-12-17 14:02:24 +01007291 if (!strcmp(args[0], "bind")) { /* new listen addresses */
7292 if (curproxy == &defproxy) {
7293 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7294 return -1;
7295 }
7296
7297 if (strchr(args[1], ':') == NULL) {
7298 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
7299 file, linenum, args[0]);
7300 return -1;
7301 }
7302 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007303 if (!curproxy->listen)
7304 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007305 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007306 return 0;
7307 }
willy tarreaub1285d52005-12-18 01:20:14 +01007308 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
7309 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
7310 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
7311 file, linenum, args[0]);
7312 return -1;
7313 }
7314 /* flush useless bits */
7315 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
7316 return 0;
7317 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007318 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01007319 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
7320 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
7321 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
7322 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007323 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007324 return -1;
7325 }
7326 }
7327 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01007328 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007329 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007330 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
7331 curproxy->state = PR_STNEW;
7332 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007333 else if (!strcmp(args[0], "cookie")) { /* cookie name */
7334 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007335// if (curproxy == &defproxy) {
7336// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7337// return -1;
7338// }
willy tarreaua41a8b42005-12-17 14:02:24 +01007339
willy tarreau9fe663a2005-12-17 13:02:59 +01007340 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007341// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7342// file, linenum);
7343// return 0;
7344 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007345 }
7346
7347 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007348 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
7349 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007350 return -1;
7351 }
7352 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007353 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007354
7355 cur_arg = 2;
7356 while (*(args[cur_arg])) {
7357 if (!strcmp(args[cur_arg], "rewrite")) {
7358 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01007359 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007360 else if (!strcmp(args[cur_arg], "indirect")) {
7361 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01007362 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007363 else if (!strcmp(args[cur_arg], "insert")) {
7364 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01007365 }
willy tarreau240afa62005-12-17 13:14:35 +01007366 else if (!strcmp(args[cur_arg], "nocache")) {
7367 curproxy->options |= PR_O_COOK_NOC;
7368 }
willy tarreaucd878942005-12-17 13:27:43 +01007369 else if (!strcmp(args[cur_arg], "postonly")) {
7370 curproxy->options |= PR_O_COOK_POST;
7371 }
willy tarreau0174f312005-12-18 01:02:42 +01007372 else if (!strcmp(args[cur_arg], "prefix")) {
7373 curproxy->options |= PR_O_COOK_PFX;
7374 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007375 else {
willy tarreau0174f312005-12-18 01:02:42 +01007376 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007377 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007378 return -1;
7379 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007380 cur_arg++;
7381 }
willy tarreau0174f312005-12-18 01:02:42 +01007382 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
7383 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
7384 file, linenum);
7385 return -1;
7386 }
7387
7388 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
7389 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007390 file, linenum);
7391 return -1;
7392 }
willy tarreau12350152005-12-18 01:03:27 +01007393 }/* end else if (!strcmp(args[0], "cookie")) */
7394 else if (!strcmp(args[0], "appsession")) { /* cookie name */
7395// if (curproxy == &defproxy) {
7396// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7397// return -1;
7398// }
7399
7400 if (curproxy->appsession_name != NULL) {
7401// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7402// file, linenum);
7403// return 0;
7404 free(curproxy->appsession_name);
7405 }
7406
7407 if (*(args[5]) == 0) {
7408 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
7409 file, linenum, args[0]);
7410 return -1;
7411 }
7412 have_appsession = 1;
7413 curproxy->appsession_name = strdup(args[1]);
7414 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
7415 curproxy->appsession_len = atoi(args[3]);
7416 curproxy->appsession_timeout = atoi(args[5]);
7417 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
7418 if (rc) {
7419 Alert("Error Init Appsession Hashtable.\n");
7420 return -1;
7421 }
7422 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01007423 else if (!strcmp(args[0], "capture")) {
7424 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
7425 // if (curproxy == &defproxy) {
7426 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7427 // return -1;
7428 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007429
willy tarreau4302f492005-12-18 01:00:37 +01007430 if (curproxy->capture_name != NULL) {
7431 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7432 // file, linenum, args[0]);
7433 // return 0;
7434 free(curproxy->capture_name);
7435 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007436
willy tarreau4302f492005-12-18 01:00:37 +01007437 if (*(args[4]) == 0) {
7438 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
7439 file, linenum, args[0]);
7440 return -1;
7441 }
7442 curproxy->capture_name = strdup(args[2]);
7443 curproxy->capture_namelen = strlen(curproxy->capture_name);
7444 curproxy->capture_len = atol(args[4]);
7445 if (curproxy->capture_len >= CAPTURE_LEN) {
7446 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
7447 file, linenum, CAPTURE_LEN - 1);
7448 curproxy->capture_len = CAPTURE_LEN - 1;
7449 }
7450 curproxy->to_log |= LW_COOKIE;
7451 }
7452 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
7453 struct cap_hdr *hdr;
7454
7455 if (curproxy == &defproxy) {
7456 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7457 return -1;
7458 }
7459
7460 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7461 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7462 file, linenum, args[0], args[1]);
7463 return -1;
7464 }
7465
7466 hdr = calloc(sizeof(struct cap_hdr), 1);
7467 hdr->next = curproxy->req_cap;
7468 hdr->name = strdup(args[3]);
7469 hdr->namelen = strlen(args[3]);
7470 hdr->len = atol(args[5]);
7471 hdr->index = curproxy->nb_req_cap++;
7472 curproxy->req_cap = hdr;
7473 curproxy->to_log |= LW_REQHDR;
7474 }
7475 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
7476 struct cap_hdr *hdr;
7477
7478 if (curproxy == &defproxy) {
7479 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7480 return -1;
7481 }
7482
7483 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7484 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7485 file, linenum, args[0], args[1]);
7486 return -1;
7487 }
7488 hdr = calloc(sizeof(struct cap_hdr), 1);
7489 hdr->next = curproxy->rsp_cap;
7490 hdr->name = strdup(args[3]);
7491 hdr->namelen = strlen(args[3]);
7492 hdr->len = atol(args[5]);
7493 hdr->index = curproxy->nb_rsp_cap++;
7494 curproxy->rsp_cap = hdr;
7495 curproxy->to_log |= LW_RSPHDR;
7496 }
7497 else {
7498 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007499 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007500 return -1;
7501 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007502 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007503 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007504 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007505 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007506 return 0;
7507 }
7508 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007509 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7510 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007511 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007512 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007513 curproxy->contimeout = atol(args[1]);
7514 }
7515 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007516 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007517 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7518 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007519 return 0;
7520 }
7521 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007522 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7523 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007524 return -1;
7525 }
7526 curproxy->clitimeout = atol(args[1]);
7527 }
7528 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007529 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007530 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007531 return 0;
7532 }
7533 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007534 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7535 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007536 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007537 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007538 curproxy->srvtimeout = atol(args[1]);
7539 }
7540 else if (!strcmp(args[0], "retries")) { /* connection retries */
7541 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007542 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
7543 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007544 return -1;
7545 }
7546 curproxy->conn_retries = atol(args[1]);
7547 }
7548 else if (!strcmp(args[0], "option")) {
7549 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007550 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007551 return -1;
7552 }
7553 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007554 /* enable reconnections to dispatch */
7555 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01007556#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007557 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007558 /* enable transparent proxy connections */
7559 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01007560#endif
7561 else if (!strcmp(args[1], "keepalive"))
7562 /* enable keep-alive */
7563 curproxy->options |= PR_O_KEEPALIVE;
7564 else if (!strcmp(args[1], "forwardfor"))
7565 /* insert x-forwarded-for field */
7566 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01007567 else if (!strcmp(args[1], "logasap"))
7568 /* log as soon as possible, without waiting for the session to complete */
7569 curproxy->options |= PR_O_LOGASAP;
7570 else if (!strcmp(args[1], "httpclose"))
7571 /* force connection: close in both directions in HTTP mode */
7572 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01007573 else if (!strcmp(args[1], "forceclose"))
7574 /* force connection: close in both directions in HTTP mode and enforce end of session */
7575 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01007576 else if (!strcmp(args[1], "checkcache"))
7577 /* require examination of cacheability of the 'set-cookie' field */
7578 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01007579 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01007580 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007581 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01007582 else if (!strcmp(args[1], "tcplog"))
7583 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007584 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01007585 else if (!strcmp(args[1], "dontlognull")) {
7586 /* don't log empty requests */
7587 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007588 }
willy tarreaub952e1d2005-12-18 01:31:20 +01007589 else if (!strcmp(args[1], "tcpka")) {
7590 /* enable TCP keep-alives on client and server sessions */
7591 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
7592 }
7593 else if (!strcmp(args[1], "clitcpka")) {
7594 /* enable TCP keep-alives on client sessions */
7595 curproxy->options |= PR_O_TCP_CLI_KA;
7596 }
7597 else if (!strcmp(args[1], "srvtcpka")) {
7598 /* enable TCP keep-alives on server sessions */
7599 curproxy->options |= PR_O_TCP_SRV_KA;
7600 }
Willy TARREAU3481c462006-03-01 22:37:57 +01007601 else if (!strcmp(args[1], "allbackups")) {
7602 /* Use all backup servers simultaneously */
7603 curproxy->options |= PR_O_USE_ALL_BK;
7604 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007605 else if (!strcmp(args[1], "httpchk")) {
7606 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007607 if (curproxy->check_req != NULL) {
7608 free(curproxy->check_req);
7609 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007610 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007611 if (!*args[2]) { /* no argument */
7612 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
7613 curproxy->check_len = strlen(DEF_CHECK_REQ);
7614 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01007615 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
7616 curproxy->check_req = (char *)malloc(reqlen);
7617 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7618 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007619 } else { /* more arguments : METHOD URI [HTTP_VER] */
7620 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
7621 if (*args[4])
7622 reqlen += strlen(args[4]);
7623 else
7624 reqlen += strlen("HTTP/1.0");
7625
7626 curproxy->check_req = (char *)malloc(reqlen);
7627 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7628 "%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 +01007629 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007630 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007631 else if (!strcmp(args[1], "persist")) {
7632 /* persist on using the server specified by the cookie, even when it's down */
7633 curproxy->options |= PR_O_PERSIST;
7634 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007635 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007636 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007637 return -1;
7638 }
7639 return 0;
7640 }
7641 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
7642 /* enable reconnections to dispatch */
7643 curproxy->options |= PR_O_REDISP;
7644 }
willy tarreaua1598082005-12-17 13:08:06 +01007645#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007646 else if (!strcmp(args[0], "transparent")) {
7647 /* enable transparent proxy connections */
7648 curproxy->options |= PR_O_TRANSP;
7649 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007650#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01007651 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
7652 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007653 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007654 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007655 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007656 curproxy->maxconn = atol(args[1]);
7657 }
7658 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
7659 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007660 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007661 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007662 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007663 curproxy->grace = atol(args[1]);
7664 }
7665 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01007666 if (curproxy == &defproxy) {
7667 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7668 return -1;
7669 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007670 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007671 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007672 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007673 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007674 curproxy->dispatch_addr = *str2sa(args[1]);
7675 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007676 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01007677 if (*(args[1])) {
7678 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007679 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01007680 }
willy tarreau1a3442d2006-03-24 21:03:20 +01007681 else if (!strcmp(args[1], "source")) {
7682 curproxy->options |= PR_O_BALANCE_SH;
7683 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007684 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01007685 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007686 return -1;
7687 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007688 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007689 else /* if no option is set, use round-robin by default */
7690 curproxy->options |= PR_O_BALANCE_RR;
7691 }
7692 else if (!strcmp(args[0], "server")) { /* server address */
7693 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007694 char *rport;
7695 char *raddr;
7696 short realport;
7697 int do_check;
7698
7699 if (curproxy == &defproxy) {
7700 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7701 return -1;
7702 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007703
willy tarreaua41a8b42005-12-17 14:02:24 +01007704 if (!*args[2]) {
7705 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007706 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007707 return -1;
7708 }
7709 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
7710 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7711 return -1;
7712 }
willy tarreau0174f312005-12-18 01:02:42 +01007713
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007714 /* the servers are linked backwards first */
7715 newsrv->next = curproxy->srv;
7716 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01007717 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007718
willy tarreau18a957c2006-04-12 19:26:23 +02007719 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01007720 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01007721 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01007722 newsrv->id = strdup(args[1]);
7723
7724 /* several ways to check the port component :
7725 * - IP => port=+0, relative
7726 * - IP: => port=+0, relative
7727 * - IP:N => port=N, absolute
7728 * - IP:+N => port=+N, relative
7729 * - IP:-N => port=-N, relative
7730 */
7731 raddr = strdup(args[2]);
7732 rport = strchr(raddr, ':');
7733 if (rport) {
7734 *rport++ = 0;
7735 realport = atol(rport);
7736 if (!isdigit((int)*rport))
7737 newsrv->state |= SRV_MAPPORTS;
7738 } else {
7739 realport = 0;
7740 newsrv->state |= SRV_MAPPORTS;
7741 }
7742
7743 newsrv->addr = *str2sa(raddr);
7744 newsrv->addr.sin_port = htons(realport);
7745 free(raddr);
7746
willy tarreau9fe663a2005-12-17 13:02:59 +01007747 newsrv->curfd = -1; /* no health-check in progress */
7748 newsrv->inter = DEF_CHKINTR;
7749 newsrv->rise = DEF_RISETIME;
7750 newsrv->fall = DEF_FALLTIME;
7751 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7752 cur_arg = 3;
7753 while (*args[cur_arg]) {
7754 if (!strcmp(args[cur_arg], "cookie")) {
7755 newsrv->cookie = strdup(args[cur_arg + 1]);
7756 newsrv->cklen = strlen(args[cur_arg + 1]);
7757 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007758 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007759 else if (!strcmp(args[cur_arg], "rise")) {
7760 newsrv->rise = atol(args[cur_arg + 1]);
7761 newsrv->health = newsrv->rise;
7762 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007763 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007764 else if (!strcmp(args[cur_arg], "fall")) {
7765 newsrv->fall = atol(args[cur_arg + 1]);
7766 cur_arg += 2;
7767 }
7768 else if (!strcmp(args[cur_arg], "inter")) {
7769 newsrv->inter = atol(args[cur_arg + 1]);
7770 cur_arg += 2;
7771 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007772 else if (!strcmp(args[cur_arg], "port")) {
7773 newsrv->check_port = atol(args[cur_arg + 1]);
7774 cur_arg += 2;
7775 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007776 else if (!strcmp(args[cur_arg], "backup")) {
7777 newsrv->state |= SRV_BACKUP;
7778 cur_arg ++;
7779 }
willy tarreaue3f023f2006-04-08 21:52:24 +02007780 else if (!strcmp(args[cur_arg], "weight")) {
7781 int w;
7782 w = atol(args[cur_arg + 1]);
7783 if (w < 1 || w > 256) {
7784 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
7785 file, linenum, newsrv->id, w);
7786 return -1;
7787 }
7788 newsrv->uweight = w - 1;
7789 cur_arg += 2;
7790 }
willy tarreau18a957c2006-04-12 19:26:23 +02007791 else if (!strcmp(args[cur_arg], "maxconn")) {
7792 newsrv->maxconn = atol(args[cur_arg + 1]);
7793 cur_arg += 2;
7794 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007795 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007796 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007797 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007798 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007799 }
willy tarreau0174f312005-12-18 01:02:42 +01007800 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7801 if (!*args[cur_arg + 1]) {
7802 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7803 file, linenum, "source");
7804 return -1;
7805 }
7806 newsrv->state |= SRV_BIND_SRC;
7807 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7808 cur_arg += 2;
7809 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007810 else {
willy tarreaue3f023f2006-04-08 21:52:24 +02007811 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port', 'source', and 'weight'.\n",
willy tarreaua41a8b42005-12-17 14:02:24 +01007812 file, linenum, newsrv->id);
7813 return -1;
7814 }
7815 }
7816
7817 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007818 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7819 newsrv->check_port = realport; /* by default */
7820 if (!newsrv->check_port) {
7821 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 +01007822 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007823 return -1;
7824 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007825 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007826 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007827
willy tarreau62084d42006-03-24 18:57:41 +01007828 if (newsrv->state & SRV_BACKUP)
7829 curproxy->srv_bck++;
7830 else
7831 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007832 }
7833 else if (!strcmp(args[0], "log")) { /* syslog server address */
7834 struct sockaddr_in *sa;
7835 int facility;
7836
7837 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7838 curproxy->logfac1 = global.logfac1;
7839 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007840 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007841 curproxy->logfac2 = global.logfac2;
7842 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007843 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007844 }
7845 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007846 int level;
7847
willy tarreau0f7af912005-12-17 12:21:26 +01007848 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7849 if (!strcmp(log_facilities[facility], args[2]))
7850 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007851
willy tarreau0f7af912005-12-17 12:21:26 +01007852 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007853 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007854 exit(1);
7855 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007856
willy tarreau8337c6b2005-12-17 13:41:01 +01007857 level = 7; /* max syslog level = debug */
7858 if (*(args[3])) {
7859 while (level >= 0 && strcmp(log_levels[level], args[3]))
7860 level--;
7861 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007862 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007863 exit(1);
7864 }
7865 }
7866
willy tarreau0f7af912005-12-17 12:21:26 +01007867 sa = str2sa(args[1]);
7868 if (!sa->sin_port)
7869 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007870
willy tarreau0f7af912005-12-17 12:21:26 +01007871 if (curproxy->logfac1 == -1) {
7872 curproxy->logsrv1 = *sa;
7873 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007874 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007875 }
7876 else if (curproxy->logfac2 == -1) {
7877 curproxy->logsrv2 = *sa;
7878 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007879 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007880 }
7881 else {
7882 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007883 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007884 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007885 }
7886 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007887 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007888 file, linenum);
7889 return -1;
7890 }
7891 }
willy tarreaua1598082005-12-17 13:08:06 +01007892 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007893 if (!*args[1]) {
7894 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007895 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007896 return -1;
7897 }
7898
7899 curproxy->source_addr = *str2sa(args[1]);
7900 curproxy->options |= PR_O_BIND_SRC;
7901 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007902 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7903 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007904 if (curproxy == &defproxy) {
7905 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7906 return -1;
7907 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007908
7909 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007910 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7911 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007912 return -1;
7913 }
7914
7915 preg = calloc(1, sizeof(regex_t));
7916 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007917 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007918 return -1;
7919 }
7920
willy tarreauc1f47532005-12-18 01:08:26 +01007921 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7922 if (err) {
7923 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7924 file, linenum, *err);
7925 return -1;
7926 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007927 }
7928 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7929 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007930 if (curproxy == &defproxy) {
7931 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7932 return -1;
7933 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007934
7935 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007936 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007937 return -1;
7938 }
7939
7940 preg = calloc(1, sizeof(regex_t));
7941 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007942 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007943 return -1;
7944 }
7945
7946 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7947 }
7948 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7949 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007950 if (curproxy == &defproxy) {
7951 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7952 return -1;
7953 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007954
7955 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007956 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007957 return -1;
7958 }
7959
7960 preg = calloc(1, sizeof(regex_t));
7961 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007962 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007963 return -1;
7964 }
7965
7966 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7967 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007968 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7969 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007970 if (curproxy == &defproxy) {
7971 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7972 return -1;
7973 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007974
7975 if (*(args[1]) == 0) {
7976 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7977 return -1;
7978 }
7979
7980 preg = calloc(1, sizeof(regex_t));
7981 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7982 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7983 return -1;
7984 }
7985
7986 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7987 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007988 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7989 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007990 if (curproxy == &defproxy) {
7991 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7992 return -1;
7993 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007994
7995 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007996 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007997 return -1;
7998 }
7999
8000 preg = calloc(1, sizeof(regex_t));
8001 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008002 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008003 return -1;
8004 }
8005
8006 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8007 }
8008 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
8009 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008010 if (curproxy == &defproxy) {
8011 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8012 return -1;
8013 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008014
8015 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008016 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8017 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008018 return -1;
8019 }
8020
8021 preg = calloc(1, sizeof(regex_t));
8022 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008023 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008024 return -1;
8025 }
8026
willy tarreauc1f47532005-12-18 01:08:26 +01008027 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8028 if (err) {
8029 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8030 file, linenum, *err);
8031 return -1;
8032 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008033 }
8034 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
8035 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008036 if (curproxy == &defproxy) {
8037 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8038 return -1;
8039 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008040
8041 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008042 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008043 return -1;
8044 }
8045
8046 preg = calloc(1, sizeof(regex_t));
8047 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008048 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008049 return -1;
8050 }
8051
8052 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8053 }
8054 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
8055 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008056 if (curproxy == &defproxy) {
8057 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8058 return -1;
8059 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008060
8061 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008062 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008063 return -1;
8064 }
8065
8066 preg = calloc(1, sizeof(regex_t));
8067 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008068 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008069 return -1;
8070 }
8071
8072 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8073 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008074 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
8075 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008076 if (curproxy == &defproxy) {
8077 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8078 return -1;
8079 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008080
8081 if (*(args[1]) == 0) {
8082 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8083 return -1;
8084 }
8085
8086 preg = calloc(1, sizeof(regex_t));
8087 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8088 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8089 return -1;
8090 }
8091
8092 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8093 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008094 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
8095 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008096 if (curproxy == &defproxy) {
8097 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8098 return -1;
8099 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008100
8101 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008102 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008103 return -1;
8104 }
8105
8106 preg = calloc(1, sizeof(regex_t));
8107 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008108 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008109 return -1;
8110 }
8111
8112 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8113 }
8114 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008115 if (curproxy == &defproxy) {
8116 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8117 return -1;
8118 }
8119
willy tarreau9fe663a2005-12-17 13:02:59 +01008120 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008121 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008122 return 0;
8123 }
8124
8125 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008126 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008127 return -1;
8128 }
8129
willy tarreau4302f492005-12-18 01:00:37 +01008130 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
8131 }
8132 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
8133 regex_t *preg;
8134
8135 if (*(args[1]) == 0 || *(args[2]) == 0) {
8136 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8137 file, linenum, args[0]);
8138 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008139 }
willy tarreau4302f492005-12-18 01:00:37 +01008140
8141 preg = calloc(1, sizeof(regex_t));
8142 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8143 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8144 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008145 }
willy tarreau4302f492005-12-18 01:00:37 +01008146
willy tarreauc1f47532005-12-18 01:08:26 +01008147 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8148 if (err) {
8149 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8150 file, linenum, *err);
8151 return -1;
8152 }
willy tarreau4302f492005-12-18 01:00:37 +01008153 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008154 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
8155 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008156 if (curproxy == &defproxy) {
8157 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8158 return -1;
8159 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008160
8161 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008162 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008163 return -1;
8164 }
willy tarreaue39cd132005-12-17 13:00:18 +01008165
willy tarreau9fe663a2005-12-17 13:02:59 +01008166 preg = calloc(1, sizeof(regex_t));
8167 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008168 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008169 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008170 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008171
willy tarreauc1f47532005-12-18 01:08:26 +01008172 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8173 if (err) {
8174 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8175 file, linenum, *err);
8176 return -1;
8177 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008178 }
willy tarreau982249e2005-12-18 00:57:06 +01008179 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
8180 regex_t *preg;
8181 if (curproxy == &defproxy) {
8182 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8183 return -1;
8184 }
8185
8186 if (*(args[1]) == 0) {
8187 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8188 return -1;
8189 }
8190
8191 preg = calloc(1, sizeof(regex_t));
8192 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8193 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8194 return -1;
8195 }
8196
willy tarreauc1f47532005-12-18 01:08:26 +01008197 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8198 if (err) {
8199 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8200 file, linenum, *err);
8201 return -1;
8202 }
willy tarreau982249e2005-12-18 00:57:06 +01008203 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008204 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01008205 regex_t *preg;
8206 if (curproxy == &defproxy) {
8207 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8208 return -1;
8209 }
willy tarreaue39cd132005-12-17 13:00:18 +01008210
willy tarreaua41a8b42005-12-17 14:02:24 +01008211 if (*(args[1]) == 0 || *(args[2]) == 0) {
8212 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8213 file, linenum, args[0]);
8214 return -1;
8215 }
willy tarreaue39cd132005-12-17 13:00:18 +01008216
willy tarreaua41a8b42005-12-17 14:02:24 +01008217 preg = calloc(1, sizeof(regex_t));
8218 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8219 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8220 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008221 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008222
willy tarreauc1f47532005-12-18 01:08:26 +01008223 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8224 if (err) {
8225 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8226 file, linenum, *err);
8227 return -1;
8228 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008229 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008230 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
8231 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008232 if (curproxy == &defproxy) {
8233 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8234 return -1;
8235 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008236
8237 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008238 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008239 return -1;
8240 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008241
willy tarreau9fe663a2005-12-17 13:02:59 +01008242 preg = calloc(1, sizeof(regex_t));
8243 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008244 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008245 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008246 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008247
willy tarreauc1f47532005-12-18 01:08:26 +01008248 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8249 if (err) {
8250 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8251 file, linenum, *err);
8252 return -1;
8253 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008254 }
willy tarreau982249e2005-12-18 00:57:06 +01008255 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
8256 regex_t *preg;
8257 if (curproxy == &defproxy) {
8258 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8259 return -1;
8260 }
8261
8262 if (*(args[1]) == 0) {
8263 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8264 return -1;
8265 }
8266
8267 preg = calloc(1, sizeof(regex_t));
8268 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8269 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8270 return -1;
8271 }
8272
willy tarreauc1f47532005-12-18 01:08:26 +01008273 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8274 if (err) {
8275 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8276 file, linenum, *err);
8277 return -1;
8278 }
willy tarreau982249e2005-12-18 00:57:06 +01008279 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008280 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008281 if (curproxy == &defproxy) {
8282 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8283 return -1;
8284 }
8285
willy tarreau9fe663a2005-12-17 13:02:59 +01008286 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008287 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008288 return 0;
8289 }
8290
8291 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008292 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008293 return -1;
8294 }
8295
8296 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
8297 }
willy tarreauc1f47532005-12-18 01:08:26 +01008298 else if (!strcmp(args[0], "errorloc") ||
8299 !strcmp(args[0], "errorloc302") ||
8300 !strcmp(args[0], "errorloc303")) { /* error location */
8301 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008302 char *err;
8303
willy tarreaueedaa9f2005-12-17 14:08:03 +01008304 // if (curproxy == &defproxy) {
8305 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8306 // return -1;
8307 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01008308
willy tarreau8337c6b2005-12-17 13:41:01 +01008309 if (*(args[2]) == 0) {
8310 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
8311 return -1;
8312 }
8313
8314 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01008315 if (!strcmp(args[0], "errorloc303")) {
8316 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
8317 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
8318 } else {
8319 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
8320 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
8321 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008322
8323 if (errnum == 400) {
8324 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008325 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008326 free(curproxy->errmsg.msg400);
8327 }
8328 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008329 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008330 }
8331 else if (errnum == 403) {
8332 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008333 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008334 free(curproxy->errmsg.msg403);
8335 }
8336 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008337 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008338 }
8339 else if (errnum == 408) {
8340 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008341 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008342 free(curproxy->errmsg.msg408);
8343 }
8344 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008345 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008346 }
8347 else if (errnum == 500) {
8348 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008349 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008350 free(curproxy->errmsg.msg500);
8351 }
8352 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008353 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008354 }
8355 else if (errnum == 502) {
8356 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008357 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008358 free(curproxy->errmsg.msg502);
8359 }
8360 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008361 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008362 }
8363 else if (errnum == 503) {
8364 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008365 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008366 free(curproxy->errmsg.msg503);
8367 }
8368 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008369 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008370 }
8371 else if (errnum == 504) {
8372 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008373 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008374 free(curproxy->errmsg.msg504);
8375 }
8376 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008377 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008378 }
8379 else {
8380 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
8381 free(err);
8382 }
8383 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008384 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008385 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01008386 return -1;
8387 }
8388 return 0;
8389}
willy tarreaue39cd132005-12-17 13:00:18 +01008390
willy tarreau5cbea6f2005-12-17 12:48:26 +01008391
willy tarreau9fe663a2005-12-17 13:02:59 +01008392/*
8393 * This function reads and parses the configuration file given in the argument.
8394 * returns 0 if OK, -1 if error.
8395 */
8396int readcfgfile(char *file) {
8397 char thisline[256];
8398 char *line;
8399 FILE *f;
8400 int linenum = 0;
8401 char *end;
8402 char *args[MAX_LINE_ARGS];
8403 int arg;
8404 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01008405 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01008406 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01008407
willy tarreau9fe663a2005-12-17 13:02:59 +01008408 struct proxy *curproxy = NULL;
8409 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01008410
willy tarreau9fe663a2005-12-17 13:02:59 +01008411 if ((f=fopen(file,"r")) == NULL)
8412 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008413
willy tarreaueedaa9f2005-12-17 14:08:03 +01008414 init_default_instance();
8415
willy tarreau9fe663a2005-12-17 13:02:59 +01008416 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
8417 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008418
willy tarreau9fe663a2005-12-17 13:02:59 +01008419 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01008420
willy tarreau9fe663a2005-12-17 13:02:59 +01008421 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01008422 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01008423 line++;
8424
8425 arg = 0;
8426 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01008427
willy tarreau9fe663a2005-12-17 13:02:59 +01008428 while (*line && arg < MAX_LINE_ARGS) {
8429 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
8430 * C equivalent value. Other combinations left unchanged (eg: \1).
8431 */
8432 if (*line == '\\') {
8433 int skip = 0;
8434 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
8435 *line = line[1];
8436 skip = 1;
8437 }
8438 else if (line[1] == 'r') {
8439 *line = '\r';
8440 skip = 1;
8441 }
8442 else if (line[1] == 'n') {
8443 *line = '\n';
8444 skip = 1;
8445 }
8446 else if (line[1] == 't') {
8447 *line = '\t';
8448 skip = 1;
8449 }
willy tarreauc1f47532005-12-18 01:08:26 +01008450 else if (line[1] == 'x') {
8451 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
8452 unsigned char hex1, hex2;
8453 hex1 = toupper(line[2]) - '0';
8454 hex2 = toupper(line[3]) - '0';
8455 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
8456 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
8457 *line = (hex1<<4) + hex2;
8458 skip = 3;
8459 }
8460 else {
8461 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
8462 return -1;
8463 }
8464 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008465 if (skip) {
8466 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
8467 end -= skip;
8468 }
8469 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008470 }
willy tarreaua1598082005-12-17 13:08:06 +01008471 else if (*line == '#' || *line == '\n' || *line == '\r') {
8472 /* end of string, end of loop */
8473 *line = 0;
8474 break;
8475 }
willy tarreauc29948c2005-12-17 13:10:27 +01008476 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008477 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01008478 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01008479 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01008480 line++;
8481 args[++arg] = line;
8482 }
8483 else {
8484 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008485 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008486 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008487
willy tarreau9fe663a2005-12-17 13:02:59 +01008488 /* empty line */
8489 if (!**args)
8490 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01008491
willy tarreau9fe663a2005-12-17 13:02:59 +01008492 /* zero out remaining args */
8493 while (++arg < MAX_LINE_ARGS) {
8494 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008495 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008496
willy tarreaua41a8b42005-12-17 14:02:24 +01008497 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01008498 confsect = CFG_LISTEN;
8499 else if (!strcmp(args[0], "global")) /* global config */
8500 confsect = CFG_GLOBAL;
8501 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01008502
willy tarreau9fe663a2005-12-17 13:02:59 +01008503 switch (confsect) {
8504 case CFG_LISTEN:
8505 if (cfg_parse_listen(file, linenum, args) < 0)
8506 return -1;
8507 break;
8508 case CFG_GLOBAL:
8509 if (cfg_parse_global(file, linenum, args) < 0)
8510 return -1;
8511 break;
8512 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01008513 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008514 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008515 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008516
8517
willy tarreau0f7af912005-12-17 12:21:26 +01008518 }
8519 fclose(f);
8520
8521 /*
8522 * Now, check for the integrity of all that we have collected.
8523 */
8524
Willy TARREAU3759f982006-03-01 22:44:17 +01008525 /* will be needed further to delay some tasks */
8526 tv_now(&now);
8527
willy tarreau0f7af912005-12-17 12:21:26 +01008528 if ((curproxy = proxy) == NULL) {
8529 Alert("parsing %s : no <listen> line. Nothing to do !\n",
8530 file);
8531 return -1;
8532 }
8533
8534 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01008535 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01008536 curproxy = curproxy->next;
8537 continue;
8538 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008539
8540 if (curproxy->listen == NULL) {
8541 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);
8542 cfgerr++;
8543 }
8544 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01008545 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01008546 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008547 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
8548 file, curproxy->id);
8549 cfgerr++;
8550 }
8551 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
8552 if (curproxy->options & PR_O_TRANSP) {
8553 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
8554 file, curproxy->id);
8555 cfgerr++;
8556 }
8557 else if (curproxy->srv == NULL) {
8558 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
8559 file, curproxy->id);
8560 cfgerr++;
8561 }
willy tarreaua1598082005-12-17 13:08:06 +01008562 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008563 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
8564 file, curproxy->id);
8565 }
8566 }
8567 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01008568 if (curproxy->cookie_name != NULL) {
8569 Warning("parsing %s : cookie will be ignored for listener %s.\n",
8570 file, curproxy->id);
8571 }
8572 if ((newsrv = curproxy->srv) != NULL) {
8573 Warning("parsing %s : servers will be ignored for listener %s.\n",
8574 file, curproxy->id);
8575 }
willy tarreaue39cd132005-12-17 13:00:18 +01008576 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008577 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
8578 file, curproxy->id);
8579 }
willy tarreaue39cd132005-12-17 13:00:18 +01008580 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008581 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
8582 file, curproxy->id);
8583 }
8584 }
8585 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
8586 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
8587 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
8588 file, curproxy->id);
8589 cfgerr++;
8590 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008591 }
willy tarreaue3f023f2006-04-08 21:52:24 +02008592
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008593 /* first, we will invert the servers list order */
8594 newsrv = NULL;
8595 while (curproxy->srv) {
8596 struct server *next;
8597
8598 next = curproxy->srv->next;
8599 curproxy->srv->next = newsrv;
8600 newsrv = curproxy->srv;
8601 if (!next)
8602 break;
8603 curproxy->srv = next;
8604 }
8605
8606 /* now, newsrv == curproxy->srv */
8607 if (newsrv) {
8608 struct server *srv;
8609 int pgcd;
8610 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02008611
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008612 /* We will factor the weights to reduce the table,
8613 * using Euclide's largest common divisor algorithm
8614 */
8615 pgcd = newsrv->uweight + 1;
8616 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
8617 int t, w;
8618
8619 w = srv->uweight + 1;
8620 while (w) {
8621 t = pgcd % w;
8622 pgcd = w;
8623 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02008624 }
willy tarreau0f7af912005-12-17 12:21:26 +01008625 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008626
8627 act = bck = 0;
8628 for (srv = newsrv; srv; srv = srv->next) {
8629 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
8630 if (srv->state & SRV_BACKUP)
8631 bck += srv->eweight + 1;
8632 else
8633 act += srv->eweight + 1;
8634 }
8635
8636 /* this is the largest map we will ever need for this servers list */
8637 if (act < bck)
8638 act = bck;
8639
8640 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
8641 /* recounts servers and their weights */
8642 recount_servers(curproxy);
8643 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01008644 }
willy tarreau25c4ea52005-12-18 00:49:49 +01008645
8646 if (curproxy->options & PR_O_LOGASAP)
8647 curproxy->to_log &= ~LW_BYTES;
8648
willy tarreau8337c6b2005-12-17 13:41:01 +01008649 if (curproxy->errmsg.msg400 == NULL) {
8650 curproxy->errmsg.msg400 = (char *)HTTP_400;
8651 curproxy->errmsg.len400 = strlen(HTTP_400);
8652 }
8653 if (curproxy->errmsg.msg403 == NULL) {
8654 curproxy->errmsg.msg403 = (char *)HTTP_403;
8655 curproxy->errmsg.len403 = strlen(HTTP_403);
8656 }
8657 if (curproxy->errmsg.msg408 == NULL) {
8658 curproxy->errmsg.msg408 = (char *)HTTP_408;
8659 curproxy->errmsg.len408 = strlen(HTTP_408);
8660 }
8661 if (curproxy->errmsg.msg500 == NULL) {
8662 curproxy->errmsg.msg500 = (char *)HTTP_500;
8663 curproxy->errmsg.len500 = strlen(HTTP_500);
8664 }
8665 if (curproxy->errmsg.msg502 == NULL) {
8666 curproxy->errmsg.msg502 = (char *)HTTP_502;
8667 curproxy->errmsg.len502 = strlen(HTTP_502);
8668 }
8669 if (curproxy->errmsg.msg503 == NULL) {
8670 curproxy->errmsg.msg503 = (char *)HTTP_503;
8671 curproxy->errmsg.len503 = strlen(HTTP_503);
8672 }
8673 if (curproxy->errmsg.msg504 == NULL) {
8674 curproxy->errmsg.msg504 = (char *)HTTP_504;
8675 curproxy->errmsg.len504 = strlen(HTTP_504);
8676 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008677
willy tarreau59a6cc22006-05-12 01:29:08 +02008678 /*
8679 * If this server supports a maxconn parameter, it needs a dedicated
8680 * tasks to fill the emptied slots when a connection leaves.
8681 */
8682 newsrv = curproxy->srv;
8683 while (newsrv != NULL) {
8684 if (newsrv->maxconn > 0) {
8685 struct task *t;
8686
8687 if ((t = pool_alloc(task)) == NULL) {
8688 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8689 return -1;
8690 }
8691
8692 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
8693 t->wq = LIST_HEAD(wait_queue[1]); /* already assigned to the eternity queue */
8694 t->state = TASK_IDLE;
8695 t->process = process_srv_queue;
8696 t->context = newsrv;
8697 newsrv->queue_mgt = t;
8698
8699 /* never run it unless specifically woken up */
8700 tv_eternity(&t->expire);
8701 task_queue(t);
8702 }
8703 newsrv = newsrv->next;
8704 }
8705
Willy TARREAU3759f982006-03-01 22:44:17 +01008706 /* now we'll start this proxy's health checks if any */
8707 /* 1- count the checkers to run simultaneously */
8708 nbchk = 0;
8709 mininter = 0;
8710 newsrv = curproxy->srv;
8711 while (newsrv != NULL) {
8712 if (newsrv->state & SRV_CHECKED) {
8713 if (!mininter || mininter > newsrv->inter)
8714 mininter = newsrv->inter;
8715 nbchk++;
8716 }
8717 newsrv = newsrv->next;
8718 }
8719
8720 /* 2- start them as far as possible from each others while respecting
8721 * their own intervals. For this, we will start them after their own
8722 * interval added to the min interval divided by the number of servers,
8723 * weighted by the server's position in the list.
8724 */
8725 if (nbchk > 0) {
8726 struct task *t;
8727 int srvpos;
8728
8729 newsrv = curproxy->srv;
8730 srvpos = 0;
8731 while (newsrv != NULL) {
8732 /* should this server be checked ? */
8733 if (newsrv->state & SRV_CHECKED) {
8734 if ((t = pool_alloc(task)) == NULL) {
8735 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8736 return -1;
8737 }
8738
8739 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02008740 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
Willy TARREAU3759f982006-03-01 22:44:17 +01008741 t->state = TASK_IDLE;
8742 t->process = process_chk;
8743 t->context = newsrv;
8744
8745 /* check this every ms */
8746 tv_delayfrom(&t->expire, &now,
8747 newsrv->inter + mininter * srvpos / nbchk);
8748 task_queue(t);
8749 //task_wakeup(&rq, t);
8750 srvpos++;
8751 }
8752 newsrv = newsrv->next;
8753 }
8754 }
8755
willy tarreau0f7af912005-12-17 12:21:26 +01008756 curproxy = curproxy->next;
8757 }
8758 if (cfgerr > 0) {
8759 Alert("Errors found in configuration file, aborting.\n");
8760 return -1;
8761 }
8762 else
8763 return 0;
8764}
8765
8766
8767/*
8768 * This function initializes all the necessary variables. It only returns
8769 * if everything is OK. If something fails, it exits.
8770 */
8771void init(int argc, char **argv) {
8772 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01008773 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01008774 char *old_argv = *argv;
8775 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008776 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008777
8778 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01008779 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01008780 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01008781 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01008782 exit(1);
8783 }
8784
willy tarreau746e26b2006-03-25 11:14:35 +01008785#ifdef HAPROXY_MEMMAX
8786 global.rlimit_memmax = HAPROXY_MEMMAX;
8787#endif
8788
Willy TARREAUa9e75f62006-03-01 22:27:48 +01008789 /* initialize the libc's localtime structures once for all so that we
8790 * won't be missing memory if we want to send alerts under OOM conditions.
8791 */
8792 tv_now(&now);
8793 localtime(&now.tv_sec);
8794
willy tarreau4302f492005-12-18 01:00:37 +01008795 /* initialize the log header encoding map : '{|}"#' should be encoded with
8796 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
8797 * URL encoding only requires '"', '#' to be encoded as well as non-
8798 * printable characters above.
8799 */
8800 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
8801 memset(url_encode_map, 0, sizeof(url_encode_map));
8802 for (i = 0; i < 32; i++) {
8803 FD_SET(i, hdr_encode_map);
8804 FD_SET(i, url_encode_map);
8805 }
8806 for (i = 127; i < 256; i++) {
8807 FD_SET(i, hdr_encode_map);
8808 FD_SET(i, url_encode_map);
8809 }
8810
8811 tmp = "\"#{|}";
8812 while (*tmp) {
8813 FD_SET(*tmp, hdr_encode_map);
8814 tmp++;
8815 }
8816
8817 tmp = "\"#";
8818 while (*tmp) {
8819 FD_SET(*tmp, url_encode_map);
8820 tmp++;
8821 }
8822
willy tarreau64a3cc32005-12-18 01:13:11 +01008823 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8824#if defined(ENABLE_POLL)
8825 cfg_polling_mechanism |= POLL_USE_POLL;
8826#endif
8827#if defined(ENABLE_EPOLL)
8828 cfg_polling_mechanism |= POLL_USE_EPOLL;
8829#endif
8830
willy tarreau0f7af912005-12-17 12:21:26 +01008831 pid = getpid();
8832 progname = *argv;
8833 while ((tmp = strchr(progname, '/')) != NULL)
8834 progname = tmp + 1;
8835
8836 argc--; argv++;
8837 while (argc > 0) {
8838 char *flag;
8839
8840 if (**argv == '-') {
8841 flag = *argv+1;
8842
8843 /* 1 arg */
8844 if (*flag == 'v') {
8845 display_version();
8846 exit(0);
8847 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008848#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008849 else if (*flag == 'd' && flag[1] == 'e')
8850 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008851#endif
8852#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008853 else if (*flag == 'd' && flag[1] == 'p')
8854 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008855#endif
willy tarreau982249e2005-12-18 00:57:06 +01008856 else if (*flag == 'V')
8857 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008858 else if (*flag == 'd' && flag[1] == 'b')
8859 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008860 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008861 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008862 else if (*flag == 'c')
8863 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008864 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008865 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008866 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008867 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01008868 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8869 /* list of pids to finish ('f') or terminate ('t') */
8870
8871 if (flag[1] == 'f')
8872 oldpids_sig = SIGUSR1; /* finish then exit */
8873 else
8874 oldpids_sig = SIGTERM; /* terminate immediately */
8875 argv++; argc--;
8876
8877 if (argc > 0) {
8878 oldpids = calloc(argc, sizeof(int));
8879 while (argc > 0) {
8880 oldpids[nb_oldpids] = atol(*argv);
8881 if (oldpids[nb_oldpids] <= 0)
8882 usage(old_argv);
8883 argc--; argv++;
8884 nb_oldpids++;
8885 }
8886 }
8887 }
willy tarreau2c513732006-04-15 19:25:16 +02008888#if STATTIME > 0
8889 else if (*flag == 's')
8890 arg_mode |= MODE_STATS;
8891 else if (*flag == 'l')
8892 arg_mode |= MODE_LOG;
8893#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008894 else { /* >=2 args */
8895 argv++; argc--;
8896 if (argc == 0)
8897 usage(old_argv);
8898
8899 switch (*flag) {
8900 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008901 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008902 case 'N' : cfg_maxpconn = atol(*argv); break;
8903 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008904 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008905 default: usage(old_argv);
8906 }
8907 }
8908 }
8909 else
8910 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008911 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008912 }
8913
willy tarreaud0fb4652005-12-18 01:32:04 +01008914 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008915 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8916 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008917
willy tarreau0f7af912005-12-17 12:21:26 +01008918 if (!cfg_cfgfile)
8919 usage(old_argv);
8920
8921 gethostname(hostname, MAX_HOSTNAME_LEN);
8922
willy tarreau12350152005-12-18 01:03:27 +01008923 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008924 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008925 if (readcfgfile(cfg_cfgfile) < 0) {
8926 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8927 exit(1);
8928 }
willy tarreau12350152005-12-18 01:03:27 +01008929 if (have_appsession)
8930 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008931
willy tarreau982249e2005-12-18 00:57:06 +01008932 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008933 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8934 exit(0);
8935 }
8936
willy tarreau9fe663a2005-12-17 13:02:59 +01008937 if (cfg_maxconn > 0)
8938 global.maxconn = cfg_maxconn;
8939
willy tarreaufe2c5c12005-12-17 14:14:34 +01008940 if (cfg_pidfile) {
8941 if (global.pidfile)
8942 free(global.pidfile);
8943 global.pidfile = strdup(cfg_pidfile);
8944 }
8945
willy tarreau9fe663a2005-12-17 13:02:59 +01008946 if (global.maxconn == 0)
8947 global.maxconn = DEFAULT_MAXCONN;
8948
Willy TARREAU203b0b62006-03-12 18:00:28 +01008949 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008950
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008951 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008952 /* command line debug mode inhibits configuration mode */
8953 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8954 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008955 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8956 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008957
8958 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8959 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8960 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8961 }
8962
8963 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008964 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8965 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008966 global.nbproc = 1;
8967 }
8968
8969 if (global.nbproc < 1)
8970 global.nbproc = 1;
8971
willy tarreau0f7af912005-12-17 12:21:26 +01008972 StaticReadEvent = (fd_set *)calloc(1,
8973 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008974 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008975 StaticWriteEvent = (fd_set *)calloc(1,
8976 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008977 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008978
8979 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008980 sizeof(struct fdtab) * (global.maxsock));
8981 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008982 fdtab[i].state = FD_STCLOSE;
8983 }
8984}
8985
8986/*
willy tarreau41310e72006-03-25 18:17:56 +01008987 * this function starts all the proxies. Its return value is composed from
8988 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8989 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008990 */
willy tarreau41310e72006-03-25 18:17:56 +01008991int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008992 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008993 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008994 int err = ERR_NONE;
8995 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008996
8997 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008998 if (curproxy->state != PR_STNEW)
8999 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01009000
willy tarreau41310e72006-03-25 18:17:56 +01009001 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01009002 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01009003 if (listener->fd != -1)
9004 continue; /* already initialized */
9005
9006 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
9007 if (verbose)
9008 Alert("cannot create listening socket for proxy %s. Aborting.\n",
9009 curproxy->id);
9010 err |= ERR_RETRYABLE;
9011 pxerr |= 1;
9012 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009013 }
willy tarreau0f7af912005-12-17 12:21:26 +01009014
willy tarreaua41a8b42005-12-17 14:02:24 +01009015 if (fd >= global.maxsock) {
9016 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
9017 curproxy->id);
9018 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009019 err |= ERR_FATAL;
9020 pxerr |= 1;
9021 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009022 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009023
willy tarreaua41a8b42005-12-17 14:02:24 +01009024 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
9025 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
9026 (char *) &one, sizeof(one)) == -1)) {
9027 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
9028 curproxy->id);
9029 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009030 err |= ERR_FATAL;
9031 pxerr |= 1;
9032 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009033 }
willy tarreau0f7af912005-12-17 12:21:26 +01009034
willy tarreaua41a8b42005-12-17 14:02:24 +01009035 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
9036 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
9037 curproxy->id);
9038 }
willy tarreau0f7af912005-12-17 12:21:26 +01009039
willy tarreaua41a8b42005-12-17 14:02:24 +01009040 if (bind(fd,
9041 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01009042 listener->addr.ss_family == AF_INET6 ?
9043 sizeof(struct sockaddr_in6) :
9044 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009045 if (verbose)
9046 Alert("cannot bind socket for proxy %s. Aborting.\n",
9047 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009048 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009049 err |= ERR_RETRYABLE;
9050 pxerr |= 1;
9051 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009052 }
willy tarreau0f7af912005-12-17 12:21:26 +01009053
willy tarreaua41a8b42005-12-17 14:02:24 +01009054 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009055 if (verbose)
9056 Alert("cannot listen to socket for proxy %s. Aborting.\n",
9057 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009058 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009059 err |= ERR_RETRYABLE;
9060 pxerr |= 1;
9061 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009062 }
willy tarreau0f7af912005-12-17 12:21:26 +01009063
willy tarreau41310e72006-03-25 18:17:56 +01009064 /* the socket is ready */
9065 listener->fd = fd;
9066
willy tarreaua41a8b42005-12-17 14:02:24 +01009067 /* the function for the accept() event */
9068 fdtab[fd].read = &event_accept;
9069 fdtab[fd].write = NULL; /* never called */
9070 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01009071 fdtab[fd].state = FD_STLISTEN;
9072 FD_SET(fd, StaticReadEvent);
9073 fd_insert(fd);
9074 listeners++;
9075 }
willy tarreau41310e72006-03-25 18:17:56 +01009076
9077 if (!pxerr) {
9078 curproxy->state = PR_STRUN;
9079 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
9080 }
willy tarreau0f7af912005-12-17 12:21:26 +01009081 }
willy tarreau41310e72006-03-25 18:17:56 +01009082
9083 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01009084}
9085
willy tarreaub952e1d2005-12-18 01:31:20 +01009086int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01009087
9088 appsess *temp1,*temp2;
9089 temp1 = (appsess *)key1;
9090 temp2 = (appsess *)key2;
9091
9092 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
9093 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
9094
9095 return (strcmp(temp1->sessid,temp2->sessid) == 0);
9096}/* end match_str */
9097
willy tarreaub952e1d2005-12-18 01:31:20 +01009098void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01009099 appsess *temp1;
9100
9101 //printf("destroy called\n");
9102 temp1 = (appsess *)data;
9103
9104 if (temp1->sessid)
9105 pool_free_to(apools.sessid, temp1->sessid);
9106
9107 if (temp1->serverid)
9108 pool_free_to(apools.serverid, temp1->serverid);
9109
9110 pool_free(appsess, temp1);
9111} /* end destroy */
9112
9113void appsession_cleanup( void )
9114{
9115 struct proxy *p = proxy;
9116
9117 while(p) {
9118 chtbl_destroy(&(p->htbl_proxy));
9119 p = p->next;
9120 }
9121}/* end appsession_cleanup() */
9122
9123void pool_destroy(void **pool)
9124{
9125 void *temp, *next;
9126 next = pool;
9127 while (next) {
9128 temp = next;
9129 next = *(void **)temp;
9130 free(temp);
9131 }
9132}/* end pool_destroy() */
9133
willy tarreaub952e1d2005-12-18 01:31:20 +01009134void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01009135 struct proxy *p = proxy;
9136 struct cap_hdr *h,*h_next;
9137 struct server *s,*s_next;
9138 struct listener *l,*l_next;
9139
9140 while (p) {
9141 if (p->id)
9142 free(p->id);
9143
9144 if (p->check_req)
9145 free(p->check_req);
9146
9147 if (p->cookie_name)
9148 free(p->cookie_name);
9149
9150 if (p->capture_name)
9151 free(p->capture_name);
9152
9153 /* only strup if the user have set in config.
9154 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01009155 if (p->errmsg.msg400) free(p->errmsg.msg400);
9156 if (p->errmsg.msg403) free(p->errmsg.msg403);
9157 if (p->errmsg.msg408) free(p->errmsg.msg408);
9158 if (p->errmsg.msg500) free(p->errmsg.msg500);
9159 if (p->errmsg.msg502) free(p->errmsg.msg502);
9160 if (p->errmsg.msg503) free(p->errmsg.msg503);
9161 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01009162 */
9163 if (p->appsession_name)
9164 free(p->appsession_name);
9165
9166 h = p->req_cap;
9167 while (h) {
9168 h_next = h->next;
9169 if (h->name)
9170 free(h->name);
9171 pool_destroy(h->pool);
9172 free(h);
9173 h = h_next;
9174 }/* end while(h) */
9175
9176 h = p->rsp_cap;
9177 while (h) {
9178 h_next = h->next;
9179 if (h->name)
9180 free(h->name);
9181
9182 pool_destroy(h->pool);
9183 free(h);
9184 h = h_next;
9185 }/* end while(h) */
9186
9187 s = p->srv;
9188 while (s) {
9189 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01009190 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01009191 free(s->id);
9192
willy tarreaub952e1d2005-12-18 01:31:20 +01009193 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01009194 free(s->cookie);
9195
9196 free(s);
9197 s = s_next;
9198 }/* end while(s) */
9199
9200 l = p->listen;
9201 while (l) {
9202 l_next = l->next;
9203 free(l);
9204 l = l_next;
9205 }/* end while(l) */
9206
9207 pool_destroy((void **) p->req_cap_pool);
9208 pool_destroy((void **) p->rsp_cap_pool);
9209 p = p->next;
9210 }/* end while(p) */
9211
9212 if (global.chroot) free(global.chroot);
9213 if (global.pidfile) free(global.pidfile);
9214
willy tarreau12350152005-12-18 01:03:27 +01009215 if (StaticReadEvent) free(StaticReadEvent);
9216 if (StaticWriteEvent) free(StaticWriteEvent);
9217 if (fdtab) free(fdtab);
9218
9219 pool_destroy(pool_session);
9220 pool_destroy(pool_buffer);
9221 pool_destroy(pool_fdtab);
9222 pool_destroy(pool_requri);
9223 pool_destroy(pool_task);
9224 pool_destroy(pool_capture);
9225 pool_destroy(pool_appsess);
9226
9227 if (have_appsession) {
9228 pool_destroy(apools.serverid);
9229 pool_destroy(apools.sessid);
9230 }
9231} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01009232
willy tarreau41310e72006-03-25 18:17:56 +01009233/* sends the signal <sig> to all pids found in <oldpids> */
9234static void tell_old_pids(int sig) {
9235 int p;
9236 for (p = 0; p < nb_oldpids; p++)
9237 kill(oldpids[p], sig);
9238}
9239
willy tarreau0f7af912005-12-17 12:21:26 +01009240int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01009241 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01009242 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009243 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009244 init(argc, argv);
9245
willy tarreau0f7af912005-12-17 12:21:26 +01009246 signal(SIGQUIT, dump);
9247 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01009248 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01009249#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01009250 signal(SIGINT, sig_int);
9251 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01009252#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009253
9254 /* on very high loads, a sigpipe sometimes happen just between the
9255 * getsockopt() which tells "it's OK to write", and the following write :-(
9256 */
willy tarreau3242e862005-12-17 12:27:53 +01009257#ifndef MSG_NOSIGNAL
9258 signal(SIGPIPE, SIG_IGN);
9259#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009260
willy tarreau41310e72006-03-25 18:17:56 +01009261 /* We will loop at most 100 times with 10 ms delay each time.
9262 * That's at most 1 second. We only send a signal to old pids
9263 * if we cannot grab at least one port.
9264 */
9265 retry = MAX_START_RETRIES;
9266 err = ERR_NONE;
9267 while (retry >= 0) {
9268 struct timeval w;
9269 err = start_proxies(retry == 0 || nb_oldpids == 0);
9270 if (err != ERR_RETRYABLE)
9271 break;
9272 if (nb_oldpids == 0)
9273 break;
9274
Willy TARREAU007aa462006-05-14 09:55:23 +02009275 /* FIXME-20060514: Solaris and OpenBSD do not support shutdown() on
9276 * listening sockets. So on those platforms, it would be wiser to
9277 * simply send SIGUSR1, which will not be undoable.
9278 */
willy tarreau41310e72006-03-25 18:17:56 +01009279 tell_old_pids(SIGTTOU);
9280 /* give some time to old processes to stop listening */
9281 w.tv_sec = 0;
9282 w.tv_usec = 10*1000;
9283 select(0, NULL, NULL, NULL, &w);
9284 retry--;
9285 }
9286
9287 /* Note: start_proxies() sends an alert when it fails. */
9288 if (err != ERR_NONE) {
9289 if (retry != MAX_START_RETRIES && nb_oldpids)
9290 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01009291 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01009292 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009293
9294 if (listeners == 0) {
9295 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009296 /* Note: we don't have to send anything to the old pids because we
9297 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01009298 exit(1);
9299 }
9300
willy tarreaudbd3bef2006-01-20 19:35:18 +01009301 /* prepare pause/play signals */
9302 signal(SIGTTOU, sig_pause);
9303 signal(SIGTTIN, sig_listen);
9304
Willy TARREAUe3283d12006-03-01 22:15:29 +01009305 if (global.mode & MODE_DAEMON) {
9306 global.mode &= ~MODE_VERBOSE;
9307 global.mode |= MODE_QUIET;
9308 }
9309
willy tarreaud0fb4652005-12-18 01:32:04 +01009310 /* MODE_QUIET can inhibit alerts and warnings below this line */
9311
9312 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01009313 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01009314 /* detach from the tty */
9315 fclose(stdin); fclose(stdout); fclose(stderr);
9316 close(0); close(1); close(2);
9317 }
willy tarreau0f7af912005-12-17 12:21:26 +01009318
willy tarreaufe2c5c12005-12-17 14:14:34 +01009319 /* open log & pid files before the chroot */
9320 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
9321 int pidfd;
9322 unlink(global.pidfile);
9323 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
9324 if (pidfd < 0) {
9325 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01009326 if (nb_oldpids)
9327 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01009328 exit(1);
9329 }
9330 pidfile = fdopen(pidfd, "w");
9331 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009332
9333 /* chroot if needed */
9334 if (global.chroot != NULL) {
9335 if (chroot(global.chroot) == -1) {
9336 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01009337 if (nb_oldpids)
9338 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01009339 }
9340 chdir("/");
9341 }
9342
willy tarreaub1285d52005-12-18 01:20:14 +01009343 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01009344 if (!global.rlimit_nofile)
9345 global.rlimit_nofile = global.maxsock;
9346
willy tarreaub1285d52005-12-18 01:20:14 +01009347 if (global.rlimit_nofile) {
9348 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
9349 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
9350 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
9351 }
willy tarreau746e26b2006-03-25 11:14:35 +01009352 }
9353
9354 if (global.rlimit_memmax) {
9355 limit.rlim_cur = limit.rlim_max =
9356 global.rlimit_memmax * 1048576 / global.nbproc;
9357#ifdef RLIMIT_AS
9358 if (setrlimit(RLIMIT_AS, &limit) == -1) {
9359 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9360 argv[0], global.rlimit_memmax);
9361 }
9362#else
9363 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
9364 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9365 argv[0], global.rlimit_memmax);
9366 }
9367#endif
willy tarreaub1285d52005-12-18 01:20:14 +01009368 }
9369
willy tarreau41310e72006-03-25 18:17:56 +01009370 if (nb_oldpids)
9371 tell_old_pids(oldpids_sig);
9372
9373 /* Note that any error at this stage will be fatal because we will not
9374 * be able to restart the old pids.
9375 */
9376
willy tarreau9fe663a2005-12-17 13:02:59 +01009377 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01009378 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009379 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
9380 exit(1);
9381 }
9382
willy tarreau036e1ce2005-12-17 13:46:33 +01009383 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009384 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
9385 exit(1);
9386 }
9387
willy tarreaub1285d52005-12-18 01:20:14 +01009388 /* check ulimits */
9389 limit.rlim_cur = limit.rlim_max = 0;
9390 getrlimit(RLIMIT_NOFILE, &limit);
9391 if (limit.rlim_cur < global.maxsock) {
9392 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",
9393 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
9394 }
9395
willy tarreau9fe663a2005-12-17 13:02:59 +01009396 if (global.mode & MODE_DAEMON) {
9397 int ret = 0;
9398 int proc;
9399
9400 /* the father launches the required number of processes */
9401 for (proc = 0; proc < global.nbproc; proc++) {
9402 ret = fork();
9403 if (ret < 0) {
9404 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009405 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01009406 exit(1); /* there has been an error */
9407 }
9408 else if (ret == 0) /* child breaks here */
9409 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009410 if (pidfile != NULL) {
9411 fprintf(pidfile, "%d\n", ret);
9412 fflush(pidfile);
9413 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009414 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01009415 /* close the pidfile both in children and father */
9416 if (pidfile != NULL)
9417 fclose(pidfile);
9418 free(global.pidfile);
9419
willy tarreau9fe663a2005-12-17 13:02:59 +01009420 if (proc == global.nbproc)
9421 exit(0); /* parent must leave */
9422
willy tarreau750a4722005-12-17 13:21:24 +01009423 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
9424 * that we can detach from the TTY. We MUST NOT do it in other cases since
9425 * it would have already be done, and 0-2 would have been affected to listening
9426 * sockets
9427 */
9428 if (!(global.mode & MODE_QUIET)) {
9429 /* detach from the tty */
9430 fclose(stdin); fclose(stdout); fclose(stderr);
9431 close(0); close(1); close(2); /* close all fd's */
9432 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
9433 }
willy tarreaua1598082005-12-17 13:08:06 +01009434 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01009435 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01009436 }
9437
willy tarreau1c2ad212005-12-18 01:11:29 +01009438#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009439 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009440 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
9441 epoll_loop(POLL_LOOP_ACTION_RUN);
9442 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009443 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009444 }
9445 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01009446 Warning("epoll() is not available. Using poll()/select() instead.\n");
9447 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009448 }
9449 }
9450#endif
9451
9452#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009453 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009454 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
9455 poll_loop(POLL_LOOP_ACTION_RUN);
9456 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009457 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009458 }
9459 else {
9460 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01009461 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009462 }
9463 }
9464#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01009465 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009466 if (select_loop(POLL_LOOP_ACTION_INIT)) {
9467 select_loop(POLL_LOOP_ACTION_RUN);
9468 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009469 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01009470 }
9471 }
9472
willy tarreau0f7af912005-12-17 12:21:26 +01009473
willy tarreau12350152005-12-18 01:03:27 +01009474 /* Free all Hash Keys and all Hash elements */
9475 appsession_cleanup();
9476 /* Do some cleanup */
9477 deinit();
9478
willy tarreau0f7af912005-12-17 12:21:26 +01009479 exit(0);
9480}
willy tarreau12350152005-12-18 01:03:27 +01009481
9482#if defined(DEBUG_HASH)
9483static void print_table(const CHTbl *htbl) {
9484
9485 ListElmt *element;
9486 int i;
9487 appsess *asession;
9488
9489 /*****************************************************************************
9490 * *
9491 * Display the chained hash table. *
9492 * *
9493 *****************************************************************************/
9494
9495 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
9496
9497 for (i = 0; i < TBLSIZ; i++) {
9498 fprintf(stdout, "Bucket[%03d]\n", i);
9499
9500 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9501 //fprintf(stdout, "%c", *(char *)list_data(element));
9502 asession = (appsess *)list_data(element);
9503 fprintf(stdout, "ELEM :%s:", asession->sessid);
9504 fprintf(stdout, " Server :%s: \n", asession->serverid);
9505 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
9506 }
9507
9508 fprintf(stdout, "\n");
9509 }
9510 return;
9511} /* end print_table */
9512#endif
9513
9514static int appsession_init(void)
9515{
9516 static int initialized = 0;
9517 int idlen;
9518 struct server *s;
9519 struct proxy *p = proxy;
9520
9521 if (!initialized) {
9522 if (!appsession_task_init()) {
9523 apools.sessid = NULL;
9524 apools.serverid = NULL;
9525 apools.ser_waste = 0;
9526 apools.ser_use = 0;
9527 apools.ser_msize = sizeof(void *);
9528 apools.ses_waste = 0;
9529 apools.ses_use = 0;
9530 apools.ses_msize = sizeof(void *);
9531 while (p) {
9532 s = p->srv;
9533 if (apools.ses_msize < p->appsession_len)
9534 apools.ses_msize = p->appsession_len;
9535 while (s) {
9536 idlen = strlen(s->id);
9537 if (apools.ser_msize < idlen)
9538 apools.ser_msize = idlen;
9539 s = s->next;
9540 }
9541 p = p->next;
9542 }
9543 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
9544 apools.ses_msize ++;
9545 }
9546 else {
9547 fprintf(stderr, "appsession_task_init failed\n");
9548 return -1;
9549 }
9550 initialized ++;
9551 }
9552 return 0;
9553}
9554
9555static int appsession_task_init(void)
9556{
9557 static int initialized = 0;
9558 struct task *t;
9559 if (!initialized) {
9560 if ((t = pool_alloc(task)) == NULL)
9561 return -1;
9562 t->next = t->prev = t->rqnext = NULL;
willy tarreau5e698ef2006-05-02 14:51:00 +02009563 t->wq = LIST_HEAD(wait_queue[0]);
willy tarreau12350152005-12-18 01:03:27 +01009564 t->state = TASK_IDLE;
9565 t->context = NULL;
9566 tv_delayfrom(&t->expire, &now, TBLCHKINT);
9567 task_queue(t);
9568 t->process = appsession_refresh;
9569 initialized ++;
9570 }
9571 return 0;
9572}
9573
9574static int appsession_refresh(struct task *t) {
9575 struct proxy *p = proxy;
9576 CHTbl *htbl;
9577 ListElmt *element, *last;
9578 int i;
9579 appsess *asession;
9580 void *data;
9581
9582 while (p) {
9583 if (p->appsession_name != NULL) {
9584 htbl = &p->htbl_proxy;
9585 /* if we ever give up the use of TBLSIZ, we need to change this */
9586 for (i = 0; i < TBLSIZ; i++) {
9587 last = NULL;
9588 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9589 asession = (appsess *)list_data(element);
9590 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
9591 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
9592 int len;
9593 /*
9594 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
9595 */
9596 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
9597 asession->sessid, asession->serverid?asession->serverid:"(null)");
9598 write(1, trash, len);
9599 }
9600 /* delete the expired element from within the hash table */
9601 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
9602 && (htbl->table[i].destroy != NULL)) {
9603 htbl->table[i].destroy(data);
9604 }
9605 if (last == NULL) {/* patient lost his head, get a new one */
9606 element = list_head(&htbl->table[i]);
9607 if (element == NULL) break; /* no heads left, go to next patient */
9608 }
9609 else
9610 element = last;
9611 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
9612 else
9613 last = element;
9614 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
9615 }
9616 }
9617 p = p->next;
9618 }
9619 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
9620 return TBLCHKINT;
9621} /* end appsession_refresh */
9622
willy tarreau18a957c2006-04-12 19:26:23 +02009623
9624/*
9625 * Local variables:
9626 * c-indent-level: 4
9627 * c-basic-offset: 4
9628 * End:
9629 */