blob: 005137030dd874e0427b7df7f7da0232b7561d16 [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 tarreau12350152005-12-18 01:03:27 +010089
willy tarreaubfad5742006-03-23 14:19:11 +010090#ifndef HAPROXY_VERSION
willy tarreaue0dd2692006-03-30 16:27:34 +020091#define HAPROXY_VERSION "1.2.11.1"
willy tarreaubfad5742006-03-23 14:19:11 +010092#endif
93
94#ifndef HAPROXY_DATE
willy tarreaue0dd2692006-03-30 16:27:34 +020095#define HAPROXY_DATE "2006/03/30"
willy tarreaubfad5742006-03-23 14:19:11 +010096#endif
willy tarreau0f7af912005-12-17 12:21:26 +010097
98/* this is for libc5 for example */
99#ifndef TCP_NODELAY
100#define TCP_NODELAY 1
101#endif
102
103#ifndef SHUT_RD
104#define SHUT_RD 0
105#endif
106
107#ifndef SHUT_WR
108#define SHUT_WR 1
109#endif
110
willy tarreau0174f312005-12-18 01:02:42 +0100111/*
112 * BUFSIZE defines the size of a read and write buffer. It is the maximum
113 * amount of bytes which can be stored by the proxy for each session. However,
114 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
115 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
116 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
117 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
118 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
119 */
120#ifndef BUFSIZE
121#define BUFSIZE 16384
122#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100123
124// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100125#ifndef MAXREWRITE
126#define MAXREWRITE (BUFSIZE / 2)
127#endif
128
willy tarreau9fe663a2005-12-17 13:02:59 +0100129#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100130#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100131
willy tarreau5cbea6f2005-12-17 12:48:26 +0100132// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100133#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100134
willy tarreaue39cd132005-12-17 13:00:18 +0100135// max # of added headers per request
136#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100137
138// max # of matches per regexp
139#define MAX_MATCH 10
140
willy tarreau0174f312005-12-18 01:02:42 +0100141// cookie delimitor in "prefix" mode. This character is inserted between the
142// persistence cookie and the original value. The '~' is allowed by RFC2965,
143// and should not be too common in server names.
144#ifndef COOKIE_DELIM
145#define COOKIE_DELIM '~'
146#endif
147
willy tarreau0f7af912005-12-17 12:21:26 +0100148#define CONN_RETRIES 3
149
willy tarreau5cbea6f2005-12-17 12:48:26 +0100150#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100151#define DEF_CHKINTR 2000
152#define DEF_FALLTIME 3
153#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100154#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100155
Willy TARREAU13032e72006-03-12 17:31:45 +0100156/* Default connections limit.
157 *
158 * A system limit can be enforced at build time in order to avoid using haproxy
159 * beyond reasonable system limits. For this, just define SYSTEM_MAXCONN to the
160 * absolute limit accepted by the system. If the configuration specifies a
161 * higher value, it will be capped to SYSTEM_MAXCONN and a warning will be
162 * emitted. The only way to override this limit will be to set it via the
163 * command-line '-n' argument.
164 */
165#ifndef SYSTEM_MAXCONN
willy tarreau9fe663a2005-12-17 13:02:59 +0100166#define DEFAULT_MAXCONN 2000
Willy TARREAU13032e72006-03-12 17:31:45 +0100167#else
168#define DEFAULT_MAXCONN SYSTEM_MAXCONN
169#endif
willy tarreau9fe663a2005-12-17 13:02:59 +0100170
willy tarreau0f7af912005-12-17 12:21:26 +0100171/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
172#define INTBITS 5
173
174/* show stats this every millisecond, 0 to disable */
175#ifndef STATTIME
176#define STATTIME 2000
177#endif
178
willy tarreau5cbea6f2005-12-17 12:48:26 +0100179/* this reduces the number of calls to select() by choosing appropriate
180 * sheduler precision in milliseconds. It should be near the minimum
181 * time that is needed by select() to collect all events. All timeouts
182 * are rounded up by adding this value prior to pass it to select().
183 */
184#define SCHEDULER_RESOLUTION 9
185
willy tarreaub952e1d2005-12-18 01:31:20 +0100186#define TIME_ETERNITY -1
187/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100188#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
189#define SETNOW(a) (*a=now)
190
willy tarreau9da061b2005-12-17 12:29:56 +0100191/****** string-specific macros and functions ******/
192/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
193#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
194
195/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
196#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
197
willy tarreau0174f312005-12-18 01:02:42 +0100198/* returns 1 only if only zero or one bit is set in X, which means that X is a
199 * power of 2, and 0 otherwise */
200#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100201/*
202 * copies at most <size-1> chars from <src> to <dst>. Last char is always
203 * set to 0, unless <size> is 0. The number of chars copied is returned
204 * (excluding the terminating zero).
205 * This code has been optimized for size and speed : on x86, it's 45 bytes
206 * long, uses only registers, and consumes only 4 cycles per char.
207 */
willy tarreau750a4722005-12-17 13:21:24 +0100208int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100209 char *orig = dst;
210 if (size) {
211 while (--size && (*dst = *src)) {
212 src++; dst++;
213 }
214 *dst = 0;
215 }
216 return dst - orig;
217}
willy tarreau9da061b2005-12-17 12:29:56 +0100218
willy tarreau4302f492005-12-18 01:00:37 +0100219/*
220 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
221 * dynamically allocated. In the first case, <__pool> is updated to point to
222 * the next element in the list.
223 */
224#define pool_alloc_from(__pool, __len) ({ \
225 void *__p; \
226 if ((__p = (__pool)) == NULL) \
227 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
228 else { \
229 __pool = *(void **)(__pool); \
230 } \
231 __p; \
232})
233
234/*
235 * Puts a memory area back to the corresponding pool.
236 * Items are chained directly through a pointer that
237 * is written in the beginning of the memory area, so
238 * there's no need for any carrier cell. This implies
239 * that each memory area is at least as big as one
240 * pointer.
241 */
242#define pool_free_to(__pool, __ptr) ({ \
243 *(void **)(__ptr) = (void *)(__pool); \
244 __pool = (void *)(__ptr); \
245})
246
247
willy tarreau0f7af912005-12-17 12:21:26 +0100248#define MEM_OPTIM
249#ifdef MEM_OPTIM
250/*
251 * Returns a pointer to type <type> taken from the
252 * pool <pool_type> or dynamically allocated. In the
253 * first case, <pool_type> is updated to point to the
254 * next element in the list.
255 */
256#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100257 void *__p; \
258 if ((__p = pool_##type) == NULL) \
259 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100260 else { \
261 pool_##type = *(void **)pool_##type; \
262 } \
willy tarreau4302f492005-12-18 01:00:37 +0100263 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100264})
265
266/*
267 * Puts a memory area back to the corresponding pool.
268 * Items are chained directly through a pointer that
269 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100270 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100271 * that each memory area is at least as big as one
272 * pointer.
273 */
274#define pool_free(type, ptr) ({ \
275 *(void **)ptr = (void *)pool_##type; \
276 pool_##type = (void *)ptr; \
277})
278
279#else
280#define pool_alloc(type) (calloc(1,sizeof_##type));
281#define pool_free(type, ptr) (free(ptr));
282#endif /* MEM_OPTIM */
283
willy tarreau5cbea6f2005-12-17 12:48:26 +0100284#define sizeof_task sizeof(struct task)
285#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100286#define sizeof_buffer sizeof(struct buffer)
287#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100288#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100289#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100290#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100291#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100292
willy tarreau5cbea6f2005-12-17 12:48:26 +0100293/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100294#define FD_STCLOSE 0
295#define FD_STLISTEN 1
296#define FD_STCONN 2
297#define FD_STREADY 3
298#define FD_STERROR 4
299
willy tarreau5cbea6f2005-12-17 12:48:26 +0100300/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100301#define TASK_IDLE 0
302#define TASK_RUNNING 1
303
willy tarreau5cbea6f2005-12-17 12:48:26 +0100304/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100305#define PR_STNEW 0
306#define PR_STIDLE 1
307#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100308#define PR_STSTOPPED 3
309#define PR_STPAUSED 4
willy tarreau0f7af912005-12-17 12:21:26 +0100310
willy tarreau5cbea6f2005-12-17 12:48:26 +0100311/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100312#define PR_MODE_TCP 0
313#define PR_MODE_HTTP 1
314#define PR_MODE_HEALTH 2
315
willy tarreau1c2ad212005-12-18 01:11:29 +0100316/* possible actions for the *poll() loops */
317#define POLL_LOOP_ACTION_INIT 0
318#define POLL_LOOP_ACTION_RUN 1
319#define POLL_LOOP_ACTION_CLEAN 2
320
willy tarreau64a3cc32005-12-18 01:13:11 +0100321/* poll mechanisms available */
322#define POLL_USE_SELECT (1<<0)
323#define POLL_USE_POLL (1<<1)
324#define POLL_USE_EPOLL (1<<2)
325
willy tarreau5cbea6f2005-12-17 12:48:26 +0100326/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100327#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
328#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
329#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
330#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
331#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
332#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
333#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
334#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau0174f312005-12-18 01:02:42 +0100335#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
336#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
337#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
338#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
339#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
340#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
341#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
342#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
343#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
344#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
345#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100346#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
347#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100348#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100349#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau1a3442d2006-03-24 21:03:20 +0100350#define PR_O_BALANCE_SH 0x00400000 /* balance on source IP hash */
351#define PR_O_BALANCE (PR_O_BALANCE_RR | PR_O_BALANCE_SH)
willy tarreau5cbea6f2005-12-17 12:48:26 +0100352
willy tarreaue39cd132005-12-17 13:00:18 +0100353/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100354#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
355#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
356#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
357#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
358#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
359#define SN_POST 0x00000020 /* the request was an HTTP POST */
willy tarreaub1285d52005-12-18 01:20:14 +0100360#define SN_MONITOR 0x00000040 /* this session comes from a monitoring system */
willy tarreau036e1ce2005-12-17 13:46:33 +0100361
362#define SN_CK_NONE 0x00000000 /* this session had no cookie */
363#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
364#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
365#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
366#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
367#define SN_CK_SHIFT 6 /* bit shift */
368
willy tarreaub1285d52005-12-18 01:20:14 +0100369#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100370#define SN_ERR_CLITO 0x00000100 /* client time-out */
371#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
372#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
373#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
374#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100375#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
376#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100377#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
378#define SN_ERR_SHIFT 8 /* bit shift */
379
380#define SN_FINST_R 0x00001000 /* session ended during client request */
381#define SN_FINST_C 0x00002000 /* session ended during server connect */
382#define SN_FINST_H 0x00003000 /* session ended during server headers */
383#define SN_FINST_D 0x00004000 /* session ended during data phase */
384#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
385#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
386#define SN_FINST_SHIFT 12 /* bit shift */
387
388#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
389#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
390#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
391#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
392#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100393#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100394#define SN_SCK_SHIFT 16 /* bit shift */
395
willy tarreau97f58572005-12-18 00:53:44 +0100396#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
397#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
398#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100399
400/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100401#define CL_STHEADERS 0
402#define CL_STDATA 1
403#define CL_STSHUTR 2
404#define CL_STSHUTW 3
405#define CL_STCLOSE 4
406
willy tarreau5cbea6f2005-12-17 12:48:26 +0100407/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100408#define SV_STIDLE 0
409#define SV_STCONN 1
410#define SV_STHEADERS 2
411#define SV_STDATA 3
412#define SV_STSHUTR 4
413#define SV_STSHUTW 5
414#define SV_STCLOSE 6
415
416/* result of an I/O event */
417#define RES_SILENT 0 /* didn't happen */
418#define RES_DATA 1 /* data were sent or received */
419#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
420#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
421
willy tarreau9fe663a2005-12-17 13:02:59 +0100422/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100423#define MODE_DEBUG 1
424#define MODE_STATS 2
425#define MODE_LOG 4
426#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100427#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100428#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100429#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100430#define MODE_STARTING 128
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100431#define MODE_FOREGROUND 256
willy tarreau5cbea6f2005-12-17 12:48:26 +0100432
433/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100434#define SRV_RUNNING 1 /* the server is UP */
435#define SRV_BACKUP 2 /* this server is a backup server */
436#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100437#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100438#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100439
willy tarreaue39cd132005-12-17 13:00:18 +0100440/* what to do when a header matches a regex */
441#define ACT_ALLOW 0 /* allow the request */
442#define ACT_REPLACE 1 /* replace the matching header */
443#define ACT_REMOVE 2 /* remove the matching header */
444#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100445#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100446
willy tarreau9fe663a2005-12-17 13:02:59 +0100447/* configuration sections */
448#define CFG_NONE 0
449#define CFG_GLOBAL 1
450#define CFG_LISTEN 2
451
willy tarreaua1598082005-12-17 13:08:06 +0100452/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100453#define LW_DATE 1 /* date */
454#define LW_CLIP 2 /* CLient IP */
455#define LW_SVIP 4 /* SerVer IP */
456#define LW_SVID 8 /* server ID */
457#define LW_REQ 16 /* http REQuest */
458#define LW_RESP 32 /* http RESPonse */
459#define LW_PXIP 64 /* proxy IP */
460#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100461#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100462#define LW_COOKIE 512 /* captured cookie */
463#define LW_REQHDR 1024 /* request header(s) */
464#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100465
willy tarreau41310e72006-03-25 18:17:56 +0100466#define ERR_NONE 0 /* no error */
467#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
468#define ERR_FATAL 2 /* fatal error, may be cumulated */
469
willy tarreau0f7af912005-12-17 12:21:26 +0100470/*********************************************************************/
471
472#define LIST_HEAD(a) ((void *)(&(a)))
473
474/*********************************************************************/
475
willy tarreau4302f492005-12-18 01:00:37 +0100476struct cap_hdr {
477 struct cap_hdr *next;
478 char *name; /* header name, case insensitive */
479 int namelen; /* length of the header name, to speed-up lookups */
480 int len; /* capture length, not including terminal zero */
481 int index; /* index in the output array */
482 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
483};
484
willy tarreau0f7af912005-12-17 12:21:26 +0100485struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100486 struct hdr_exp *next;
487 regex_t *preg; /* expression to look for */
488 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
489 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100490};
491
492struct buffer {
493 unsigned int l; /* data length */
494 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100495 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100496 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100497 char data[BUFSIZE];
498};
499
500struct server {
501 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100502 int state; /* server state (SRV_*) */
503 int cklen; /* the len of the cookie, to speed up checks */
504 char *cookie; /* the id set in the cookie */
505 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100506 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100507 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100508 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100509 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100510 int rise, fall; /* time in iterations */
511 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100512 int result; /* 0 = connect OK, -1 = connect KO */
513 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreauc1364612006-04-07 16:28:28 +0200514 int cur_sess; /* number of currently active sessions (including syn_sent) */
515 unsigned int cum_sess; /* cumulated number of sessions really sent to this server */
willy tarreau535ae7a2005-12-17 12:58:00 +0100516 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100517};
518
willy tarreau5cbea6f2005-12-17 12:48:26 +0100519/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100520struct task {
521 struct task *next, *prev; /* chaining ... */
522 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100523 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100524 int state; /* task state : IDLE or RUNNING */
525 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100526 int (*process)(struct task *t); /* the function which processes the task */
527 void *context; /* the task's context */
528};
529
530/* WARNING: if new fields are added, they must be initialized in event_accept() */
531struct session {
532 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100533 /* application specific below */
534 struct timeval crexpire; /* expiration date for a client read */
535 struct timeval cwexpire; /* expiration date for a client write */
536 struct timeval srexpire; /* expiration date for a server read */
537 struct timeval swexpire; /* expiration date for a server write */
538 struct timeval cnexpire; /* expiration date for a connect */
539 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
540 struct proxy *proxy; /* the proxy this socket belongs to */
541 int cli_fd; /* the client side fd */
542 int srv_fd; /* the server side fd */
543 int cli_state; /* state of the client side */
544 int srv_state; /* state of the server side */
545 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100546 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100547 struct buffer *req; /* request buffer */
548 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100549 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100550 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100551 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100552 char **req_cap; /* array of captured request headers (may be NULL) */
553 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100554 struct {
555 int logwait; /* log fields waiting to be collected : LW_* */
556 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
557 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
558 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
559 long t_data; /* delay before the first data byte from the server ... */
560 unsigned long t_close; /* total session duration */
561 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100562 char *cli_cookie; /* cookie presented by the client, in capture mode */
563 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100564 int status; /* HTTP status from the server, negative if from proxy */
565 long long bytes; /* number of bytes transferred from the server */
566 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100567 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100568};
569
willy tarreaua41a8b42005-12-17 14:02:24 +0100570struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100571 int fd; /* the listen socket */
572 struct sockaddr_storage addr; /* the address we listen to */
573 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100574};
575
576
willy tarreau0f7af912005-12-17 12:21:26 +0100577struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100578 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100579 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 +0100580 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100581 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100582 struct server *srv, *cursrv; /* known servers, current server */
willy tarreau62084d42006-03-24 18:57:41 +0100583 int srv_act, srv_bck; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100584 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100585 int cookie_len; /* strlen(cookie_name), computed only once */
586 char *appsession_name; /* name of the cookie to look for */
587 int appsession_name_len; /* strlen(appsession_name), computed only once */
588 int appsession_len; /* length of the appsession cookie value to be used */
589 int appsession_timeout;
590 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100591 char *capture_name; /* beginning of the name of the cookie to capture */
592 int capture_namelen; /* length of the cookie name to match */
593 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100594 int clitimeout; /* client I/O timeout (in milliseconds) */
595 int srvtimeout; /* server I/O timeout (in milliseconds) */
596 int contimeout; /* connect timeout (in milliseconds) */
597 char *id; /* proxy id */
598 int nbconn; /* # of active sessions */
599 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100600 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100601 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100602 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100603 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100604 struct proxy *next;
605 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100606 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100607 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100608 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100609 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100610 int nb_reqadd, nb_rspadd;
611 struct hdr_exp *req_exp; /* regular expressions for request headers */
612 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100613 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
614 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
615 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
616 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100617 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100618 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100619 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
620 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100621 struct {
622 char *msg400; /* message for error 400 */
623 int len400; /* message length for error 400 */
624 char *msg403; /* message for error 403 */
625 int len403; /* message length for error 403 */
626 char *msg408; /* message for error 408 */
627 int len408; /* message length for error 408 */
628 char *msg500; /* message for error 500 */
629 int len500; /* message length for error 500 */
630 char *msg502; /* message for error 502 */
631 int len502; /* message length for error 502 */
632 char *msg503; /* message for error 503 */
633 int len503; /* message length for error 503 */
634 char *msg504; /* message for error 504 */
635 int len504; /* message length for error 504 */
636 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100637};
638
639/* info about one given fd */
640struct fdtab {
641 int (*read)(int fd); /* read function */
642 int (*write)(int fd); /* write function */
643 struct task *owner; /* the session (or proxy) associated with this fd */
644 int state; /* the state of this fd */
645};
646
647/*********************************************************************/
648
willy tarreaub952e1d2005-12-18 01:31:20 +0100649int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100650int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100651char *cfg_cfgfile = NULL; /* configuration file */
652char *progname = NULL; /* program name */
653int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100654
655/* global options */
656static struct {
657 int uid;
658 int gid;
659 int nbproc;
660 int maxconn;
661 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100662 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100663 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100664 int mode;
665 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100666 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100667 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100668 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100669 struct sockaddr_in logsrv1, logsrv2;
670} global = {
671 logfac1 : -1,
672 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100673 loglev1 : 7, /* max syslog level : debug */
674 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100675 /* others NULL OK */
676};
677
willy tarreau0f7af912005-12-17 12:21:26 +0100678/*********************************************************************/
679
willy tarreau1c2ad212005-12-18 01:11:29 +0100680fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100681 *StaticWriteEvent;
682
willy tarreau64a3cc32005-12-18 01:13:11 +0100683int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100684
willy tarreau0f7af912005-12-17 12:21:26 +0100685void **pool_session = NULL,
686 **pool_buffer = NULL,
687 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100688 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100689 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100690 **pool_capture = NULL,
691 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100692
693struct proxy *proxy = NULL; /* list of all existing proxies */
694struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100695struct task *rq = NULL; /* global run queue */
696struct task wait_queue = { /* global wait queue */
697 prev:LIST_HEAD(wait_queue),
698 next:LIST_HEAD(wait_queue)
699};
willy tarreau0f7af912005-12-17 12:21:26 +0100700
willy tarreau0f7af912005-12-17 12:21:26 +0100701static int totalconn = 0; /* total # of terminated sessions */
702static int actconn = 0; /* # of active sessions */
703static int maxfd = 0; /* # of the highest fd + 1 */
704static int listeners = 0; /* # of listeners */
705static int stopping = 0; /* non zero means stopping in progress */
706static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100707static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100708
willy tarreau53e99702006-03-25 18:53:50 +0100709/* Here we store informations about the pids of the processes we may pause
710 * or kill. We will send them a signal every 10 ms until we can bind to all
711 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100712 */
willy tarreau53e99702006-03-25 18:53:50 +0100713#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100714static int nb_oldpids = 0;
715static int *oldpids = NULL;
716static int oldpids_sig; /* use USR1 or TERM */
717
willy tarreau08dedbe2005-12-18 01:13:48 +0100718#if defined(ENABLE_EPOLL)
719/* FIXME: this is dirty, but at the moment, there's no other solution to remove
720 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
721 * structure with pointers to functions such as init_fd() and close_fd(), plus
722 * a private structure with several pointers to places such as below.
723 */
724
725static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
726#endif
727
willy tarreau0f7af912005-12-17 12:21:26 +0100728static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100729/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100730static char trash[BUFSIZE];
731
willy tarreaudd07e972005-12-18 00:48:48 +0100732const int zero = 0;
733const int one = 1;
734
willy tarreau0f7af912005-12-17 12:21:26 +0100735/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100736 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100737 */
738
739#define MAX_SYSLOG_LEN 1024
740#define NB_LOG_FACILITIES 24
741const char *log_facilities[NB_LOG_FACILITIES] = {
742 "kern", "user", "mail", "daemon",
743 "auth", "syslog", "lpr", "news",
744 "uucp", "cron", "auth2", "ftp",
745 "ntp", "audit", "alert", "cron2",
746 "local0", "local1", "local2", "local3",
747 "local4", "local5", "local6", "local7"
748};
749
750
751#define NB_LOG_LEVELS 8
752const char *log_levels[NB_LOG_LEVELS] = {
753 "emerg", "alert", "crit", "err",
754 "warning", "notice", "info", "debug"
755};
756
757#define SYSLOG_PORT 514
758
759const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
760 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100761
willy tarreaub1285d52005-12-18 01:20:14 +0100762const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100763const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
764const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
765const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
766 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
767 unknown, Set-cookie Rewritten */
768
willy tarreau0f7af912005-12-17 12:21:26 +0100769#define MAX_HOSTNAME_LEN 32
770static char hostname[MAX_HOSTNAME_LEN] = "";
771
willy tarreau8337c6b2005-12-17 13:41:01 +0100772const char *HTTP_302 =
773 "HTTP/1.0 302 Found\r\n"
774 "Cache-Control: no-cache\r\n"
775 "Connection: close\r\n"
776 "Location: "; /* not terminated since it will be concatenated with the URL */
777
willy tarreauc1f47532005-12-18 01:08:26 +0100778/* same as 302 except that the browser MUST retry with the GET method */
779const char *HTTP_303 =
780 "HTTP/1.0 303 See Other\r\n"
781 "Cache-Control: no-cache\r\n"
782 "Connection: close\r\n"
783 "Location: "; /* not terminated since it will be concatenated with the URL */
784
willy tarreaua1598082005-12-17 13:08:06 +0100785const char *HTTP_400 =
786 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100787 "Cache-Control: no-cache\r\n"
788 "Connection: close\r\n"
789 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100790 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100791
willy tarreaua1598082005-12-17 13:08:06 +0100792const char *HTTP_403 =
793 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100794 "Cache-Control: no-cache\r\n"
795 "Connection: close\r\n"
796 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100797 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
798
willy tarreau8337c6b2005-12-17 13:41:01 +0100799const char *HTTP_408 =
800 "HTTP/1.0 408 Request Time-out\r\n"
801 "Cache-Control: no-cache\r\n"
802 "Connection: close\r\n"
803 "\r\n"
804 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
805
willy tarreau750a4722005-12-17 13:21:24 +0100806const char *HTTP_500 =
807 "HTTP/1.0 500 Server Error\r\n"
808 "Cache-Control: no-cache\r\n"
809 "Connection: close\r\n"
810 "\r\n"
811 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100812
813const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100814 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100815 "Cache-Control: no-cache\r\n"
816 "Connection: close\r\n"
817 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100818 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
819
820const char *HTTP_503 =
821 "HTTP/1.0 503 Service Unavailable\r\n"
822 "Cache-Control: no-cache\r\n"
823 "Connection: close\r\n"
824 "\r\n"
825 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
826
827const char *HTTP_504 =
828 "HTTP/1.0 504 Gateway Time-out\r\n"
829 "Cache-Control: no-cache\r\n"
830 "Connection: close\r\n"
831 "\r\n"
832 "<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 +0100833
willy tarreau0f7af912005-12-17 12:21:26 +0100834/*********************************************************************/
835/* statistics ******************************************************/
836/*********************************************************************/
837
willy tarreau750a4722005-12-17 13:21:24 +0100838#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100839static int stats_tsk_lsrch, stats_tsk_rsrch,
840 stats_tsk_good, stats_tsk_right, stats_tsk_left,
841 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100842#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100843
844
845/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100846/* debugging *******************************************************/
847/*********************************************************************/
848#ifdef DEBUG_FULL
849static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
850static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
851#endif
852
853/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100854/* function prototypes *********************************************/
855/*********************************************************************/
856
857int event_accept(int fd);
858int event_cli_read(int fd);
859int event_cli_write(int fd);
860int event_srv_read(int fd);
861int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100862int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100863
willy tarreau12350152005-12-18 01:03:27 +0100864static int appsession_task_init(void);
865static int appsession_init(void);
866static int appsession_refresh(struct task *t);
867
willy tarreau0f7af912005-12-17 12:21:26 +0100868/*********************************************************************/
869/* general purpose functions ***************************************/
870/*********************************************************************/
871
872void display_version() {
873 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100874 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100875}
876
877/*
878 * This function prints the command line usage and exits
879 */
880void usage(char *name) {
881 display_version();
882 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100883 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100884#if STATTIME > 0
885 "sl"
886#endif
willy tarreau746e26b2006-03-25 11:14:35 +0100887 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
888 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100889 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100890 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +0100891 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100892#if STATTIME > 0
893 " -s enables statistics output\n"
894 " -l enables long statistics format\n"
895#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100896 " -D goes daemon ; implies -q\n"
897 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100898 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100899 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +0100900 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100901 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100902 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100903#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100904 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100905#endif
906#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100907 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100908#endif
willy tarreau53e99702006-03-25 18:53:50 +0100909 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100910 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100911 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100912 exit(1);
913}
914
915
916/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100917 * Displays the message on stderr with the date and pid. Overrides the quiet
918 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100919 */
920void Alert(char *fmt, ...) {
921 va_list argp;
922 struct timeval tv;
923 struct tm *tm;
924
willy tarreaud0fb4652005-12-18 01:32:04 +0100925 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100926 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100927
willy tarreau5cbea6f2005-12-17 12:48:26 +0100928 gettimeofday(&tv, NULL);
929 tm=localtime(&tv.tv_sec);
930 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100931 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100932 vfprintf(stderr, fmt, argp);
933 fflush(stderr);
934 va_end(argp);
935 }
willy tarreau0f7af912005-12-17 12:21:26 +0100936}
937
938
939/*
940 * Displays the message on stderr with the date and pid.
941 */
942void Warning(char *fmt, ...) {
943 va_list argp;
944 struct timeval tv;
945 struct tm *tm;
946
willy tarreau982249e2005-12-18 00:57:06 +0100947 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100948 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100949
willy tarreau5cbea6f2005-12-17 12:48:26 +0100950 gettimeofday(&tv, NULL);
951 tm=localtime(&tv.tv_sec);
952 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100953 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100954 vfprintf(stderr, fmt, argp);
955 fflush(stderr);
956 va_end(argp);
957 }
958}
959
960/*
961 * Displays the message on <out> only if quiet mode is not set.
962 */
963void qfprintf(FILE *out, char *fmt, ...) {
964 va_list argp;
965
willy tarreau982249e2005-12-18 00:57:06 +0100966 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100967 va_start(argp, fmt);
968 vfprintf(out, fmt, argp);
969 fflush(out);
970 va_end(argp);
971 }
willy tarreau0f7af912005-12-17 12:21:26 +0100972}
973
974
975/*
976 * converts <str> to a struct sockaddr_in* which is locally allocated.
977 * The format is "addr:port", where "addr" can be empty or "*" to indicate
978 * INADDR_ANY.
979 */
980struct sockaddr_in *str2sa(char *str) {
981 static struct sockaddr_in sa;
982 char *c;
983 int port;
984
willy tarreaua1598082005-12-17 13:08:06 +0100985 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100986 str=strdup(str);
987
988 if ((c=strrchr(str,':')) != NULL) {
989 *c++=0;
990 port=atol(c);
991 }
992 else
993 port=0;
994
995 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
996 sa.sin_addr.s_addr = INADDR_ANY;
997 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100998 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100999 struct hostent *he;
1000
1001 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001002 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001003 }
1004 else
1005 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1006 }
1007 sa.sin_port=htons(port);
1008 sa.sin_family=AF_INET;
1009
1010 free(str);
1011 return &sa;
1012}
1013
willy tarreaub1285d52005-12-18 01:20:14 +01001014/*
1015 * converts <str> to a two struct in_addr* which are locally allocated.
1016 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1017 * is optionnal and either in the dotted or CIDR notation.
1018 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1019 */
1020int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1021 char *c;
1022 unsigned long len;
1023
1024 memset(mask, 0, sizeof(*mask));
1025 memset(addr, 0, sizeof(*addr));
1026 str=strdup(str);
1027
1028 if ((c = strrchr(str, '/')) != NULL) {
1029 *c++ = 0;
1030 /* c points to the mask */
1031 if (strchr(c, '.') != NULL) { /* dotted notation */
1032 if (!inet_pton(AF_INET, c, mask))
1033 return 0;
1034 }
1035 else { /* mask length */
1036 char *err;
1037 len = strtol(c, &err, 10);
1038 if (!*c || (err && *err) || (unsigned)len > 32)
1039 return 0;
1040 if (len)
1041 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1042 else
1043 mask->s_addr = 0;
1044 }
1045 }
1046 else {
1047 mask->s_addr = 0xFFFFFFFF;
1048 }
1049 if (!inet_pton(AF_INET, str, addr)) {
1050 struct hostent *he;
1051
1052 if ((he = gethostbyname(str)) == NULL) {
1053 return 0;
1054 }
1055 else
1056 *addr = *(struct in_addr *) *(he->h_addr_list);
1057 }
1058 free(str);
1059 return 1;
1060}
1061
willy tarreau9fe663a2005-12-17 13:02:59 +01001062
1063/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001064 * converts <str> to a list of listeners which are dynamically allocated.
1065 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1066 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1067 * - <port> is a numerical port from 1 to 65535 ;
1068 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1069 * This can be repeated as many times as necessary, separated by a coma.
1070 * The <tail> argument is a pointer to a current list which should be appended
1071 * to the tail of the new list. The pointer to the new list is returned.
1072 */
1073struct listener *str2listener(char *str, struct listener *tail) {
1074 struct listener *l;
1075 char *c, *next, *range, *dupstr;
1076 int port, end;
1077
1078 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001079
willy tarreaua41a8b42005-12-17 14:02:24 +01001080 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001081 struct sockaddr_storage ss;
1082
willy tarreaua41a8b42005-12-17 14:02:24 +01001083 str = next;
1084 /* 1) look for the end of the first address */
1085 if ((next = strrchr(str, ',')) != NULL) {
1086 *next++ = 0;
1087 }
1088
willy tarreau8a86dbf2005-12-18 00:45:59 +01001089 /* 2) look for the addr/port delimiter, it's the last colon. */
1090 if ((range = strrchr(str, ':')) == NULL) {
1091 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001092 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001093 }
1094
1095 *range++ = 0;
1096
1097 if (strrchr(str, ':') != NULL) {
1098 /* IPv6 address contains ':' */
1099 memset(&ss, 0, sizeof(ss));
1100 ss.ss_family = AF_INET6;
1101
1102 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1103 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001104 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001105 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001106 }
1107 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001108 memset(&ss, 0, sizeof(ss));
1109 ss.ss_family = AF_INET;
1110
1111 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1112 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1113 }
1114 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1115 struct hostent *he;
1116
1117 if ((he = gethostbyname(str)) == NULL) {
1118 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001119 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001120 }
1121 else
1122 ((struct sockaddr_in *)&ss)->sin_addr =
1123 *(struct in_addr *) *(he->h_addr_list);
1124 }
1125 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001126
1127 /* 3) look for the port-end delimiter */
1128 if ((c = strchr(range, '-')) != NULL) {
1129 *c++ = 0;
1130 end = atol(c);
1131 }
1132 else {
1133 end = atol(range);
1134 }
1135
willy tarreaud0fb4652005-12-18 01:32:04 +01001136 port = atol(range);
1137
1138 if (port < 1 || port > 65535) {
1139 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1140 goto fail;
1141 }
1142
1143 if (end < 1 || end > 65535) {
1144 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1145 goto fail;
1146 }
1147
1148 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001149 l = (struct listener *)calloc(1, sizeof(struct listener));
1150 l->next = tail;
1151 tail = l;
1152
willy tarreau41310e72006-03-25 18:17:56 +01001153 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001154 l->addr = ss;
1155 if (ss.ss_family == AF_INET6)
1156 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1157 else
1158 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1159
willy tarreaua41a8b42005-12-17 14:02:24 +01001160 } /* end for(port) */
1161 } /* end while(next) */
1162 free(dupstr);
1163 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001164 fail:
1165 free(dupstr);
1166 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001167}
1168
willy tarreau4302f492005-12-18 01:00:37 +01001169
1170#define FD_SETS_ARE_BITFIELDS
1171#ifdef FD_SETS_ARE_BITFIELDS
1172/*
1173 * This map is used with all the FD_* macros to check whether a particular bit
1174 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1175 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1176 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1177 * exclusively to the macros.
1178 */
1179fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1180fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1181
1182#else
1183#error "Check if your OS uses bitfields for fd_sets"
1184#endif
1185
1186/* will try to encode the string <string> replacing all characters tagged in
1187 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1188 * prefixed by <escape>, and will store the result between <start> (included
1189 *) and <stop> (excluded), and will always terminate the string with a '\0'
1190 * before <stop>. The position of the '\0' is returned if the conversion
1191 * completes. If bytes are missing between <start> and <stop>, then the
1192 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1193 * cannot even be stored so we return <start> without writing the 0.
1194 * The input string must also be zero-terminated.
1195 */
1196char hextab[16] = "0123456789ABCDEF";
1197char *encode_string(char *start, char *stop,
1198 const char escape, const fd_set *map,
1199 const char *string)
1200{
1201 if (start < stop) {
1202 stop--; /* reserve one byte for the final '\0' */
1203 while (start < stop && *string != 0) {
1204 if (!FD_ISSET((unsigned char)(*string), map))
1205 *start++ = *string;
1206 else {
1207 if (start + 3 >= stop)
1208 break;
1209 *start++ = escape;
1210 *start++ = hextab[(*string >> 4) & 15];
1211 *start++ = hextab[*string & 15];
1212 }
1213 string++;
1214 }
1215 *start = '\0';
1216 }
1217 return start;
1218}
willy tarreaua41a8b42005-12-17 14:02:24 +01001219
1220/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001221 * This function sends a syslog message to both log servers of a proxy,
1222 * or to global log servers if the proxy is NULL.
1223 * It also tries not to waste too much time computing the message header.
1224 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001225 */
1226void send_log(struct proxy *p, int level, char *message, ...) {
1227 static int logfd = -1; /* syslog UDP socket */
1228 static long tvsec = -1; /* to force the string to be initialized */
1229 struct timeval tv;
1230 va_list argp;
1231 static char logmsg[MAX_SYSLOG_LEN];
1232 static char *dataptr = NULL;
1233 int fac_level;
1234 int hdr_len, data_len;
1235 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001236 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001237 int nbloggers = 0;
1238 char *log_ptr;
1239
1240 if (logfd < 0) {
1241 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1242 return;
1243 }
1244
1245 if (level < 0 || progname == NULL || message == NULL)
1246 return;
1247
1248 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001249 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001250 /* this string is rebuild only once a second */
1251 struct tm *tm = localtime(&tv.tv_sec);
1252 tvsec = tv.tv_sec;
1253
willy tarreauc29948c2005-12-17 13:10:27 +01001254 hdr_len = snprintf(logmsg, sizeof(logmsg),
1255 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1256 monthname[tm->tm_mon],
1257 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1258 progname, pid);
1259 /* WARNING: depending upon implementations, snprintf may return
1260 * either -1 or the number of bytes that would be needed to store
1261 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001262 */
willy tarreauc29948c2005-12-17 13:10:27 +01001263 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1264 hdr_len = sizeof(logmsg);
1265
1266 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001267 }
1268
1269 va_start(argp, message);
1270 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001271 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1272 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001273 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001274 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001275
1276 if (p == NULL) {
1277 if (global.logfac1 >= 0) {
1278 sa[nbloggers] = &global.logsrv1;
1279 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001280 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001281 nbloggers++;
1282 }
1283 if (global.logfac2 >= 0) {
1284 sa[nbloggers] = &global.logsrv2;
1285 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001286 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001287 nbloggers++;
1288 }
1289 } else {
1290 if (p->logfac1 >= 0) {
1291 sa[nbloggers] = &p->logsrv1;
1292 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001293 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001294 nbloggers++;
1295 }
1296 if (p->logfac2 >= 0) {
1297 sa[nbloggers] = &p->logsrv2;
1298 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001299 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001300 nbloggers++;
1301 }
1302 }
1303
1304 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001305 /* we can filter the level of the messages that are sent to each logger */
1306 if (level > loglevel[nbloggers])
1307 continue;
1308
willy tarreauc29948c2005-12-17 13:10:27 +01001309 /* For each target, we may have a different facility.
1310 * We can also have a different log level for each message.
1311 * This induces variations in the message header length.
1312 * Since we don't want to recompute it each time, nor copy it every
1313 * time, we only change the facility in the pre-computed header,
1314 * and we change the pointer to the header accordingly.
1315 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001316 fac_level = (facilities[nbloggers] << 3) + level;
1317 log_ptr = logmsg + 3; /* last digit of the log level */
1318 do {
1319 *log_ptr = '0' + fac_level % 10;
1320 fac_level /= 10;
1321 log_ptr--;
1322 } while (fac_level && log_ptr > logmsg);
1323 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001324
willy tarreauc29948c2005-12-17 13:10:27 +01001325 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001326
1327#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001328 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001329 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1330#else
willy tarreauc29948c2005-12-17 13:10:27 +01001331 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001332 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1333#endif
1334 }
willy tarreau0f7af912005-12-17 12:21:26 +01001335}
1336
1337
1338/* sets <tv> to the current time */
1339static inline struct timeval *tv_now(struct timeval *tv) {
1340 if (tv)
1341 gettimeofday(tv, NULL);
1342 return tv;
1343}
1344
1345/*
1346 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1347 */
1348static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1349 if (!tv || !from)
1350 return NULL;
1351 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1352 tv->tv_sec = from->tv_sec + (ms/1000);
1353 while (tv->tv_usec >= 1000000) {
1354 tv->tv_usec -= 1000000;
1355 tv->tv_sec++;
1356 }
1357 return tv;
1358}
1359
1360/*
1361 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001362 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001363 */
1364static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001365 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001366 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001367 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001368 return 1;
1369 else if (tv1->tv_usec < tv2->tv_usec)
1370 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001371 else if (tv1->tv_usec > tv2->tv_usec)
1372 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001373 else
1374 return 0;
1375}
1376
1377/*
1378 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001379 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001380 */
1381unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1382 int cmp;
1383 unsigned long ret;
1384
1385
willy tarreauef900ab2005-12-17 12:52:52 +01001386 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001387 if (!cmp)
1388 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001389 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001390 struct timeval *tmp = tv1;
1391 tv1 = tv2;
1392 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001393 }
willy tarreauef900ab2005-12-17 12:52:52 +01001394 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001395 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001396 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001397 else
willy tarreauef900ab2005-12-17 12:52:52 +01001398 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001399 return (unsigned long) ret;
1400}
1401
1402/*
willy tarreau750a4722005-12-17 13:21:24 +01001403 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001404 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001405 */
1406static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1407 unsigned long ret;
1408
willy tarreau6e682ce2005-12-17 13:26:49 +01001409 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1410 if (tv2->tv_usec > tv1->tv_usec)
1411 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001412 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001413 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001414 return (unsigned long) ret;
1415}
1416
1417/*
willy tarreau0f7af912005-12-17 12:21:26 +01001418 * 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 +01001419 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001420 */
1421static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001422 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001423 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001424 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001425 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001426 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001427 else
1428 return 0;
1429 }
willy tarreau0f7af912005-12-17 12:21:26 +01001430 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001431 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001432 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001433 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001434 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001435 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001436 else
1437 return 0;
1438}
1439
1440/*
1441 * returns the remaining time between tv1=now and event=tv2
1442 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001443 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001444 */
1445static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1446 unsigned long ret;
1447
willy tarreau0f7af912005-12-17 12:21:26 +01001448 if (tv_cmp_ms(tv1, tv2) >= 0)
1449 return 0; /* event elapsed */
1450
willy tarreauef900ab2005-12-17 12:52:52 +01001451 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001452 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001453 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001454 else
willy tarreauef900ab2005-12-17 12:52:52 +01001455 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001456 return (unsigned long) ret;
1457}
1458
1459
1460/*
1461 * zeroes a struct timeval
1462 */
1463
1464static inline struct timeval *tv_eternity(struct timeval *tv) {
1465 tv->tv_sec = tv->tv_usec = 0;
1466 return tv;
1467}
1468
1469/*
1470 * returns 1 if tv is null, else 0
1471 */
1472static inline int tv_iseternity(struct timeval *tv) {
1473 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1474 return 1;
1475 else
1476 return 0;
1477}
1478
1479/*
1480 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1481 * considering that 0 is the eternity.
1482 */
1483static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1484 if (tv_iseternity(tv1))
1485 if (tv_iseternity(tv2))
1486 return 0; /* same */
1487 else
1488 return 1; /* tv1 later than tv2 */
1489 else if (tv_iseternity(tv2))
1490 return -1; /* tv2 later than tv1 */
1491
1492 if (tv1->tv_sec > tv2->tv_sec)
1493 return 1;
1494 else if (tv1->tv_sec < tv2->tv_sec)
1495 return -1;
1496 else if (tv1->tv_usec > tv2->tv_usec)
1497 return 1;
1498 else if (tv1->tv_usec < tv2->tv_usec)
1499 return -1;
1500 else
1501 return 0;
1502}
1503
1504/*
1505 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1506 * considering that 0 is the eternity.
1507 */
1508static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1509 if (tv_iseternity(tv1))
1510 if (tv_iseternity(tv2))
1511 return 0; /* same */
1512 else
1513 return 1; /* tv1 later than tv2 */
1514 else if (tv_iseternity(tv2))
1515 return -1; /* tv2 later than tv1 */
1516
willy tarreauefae1842005-12-17 12:51:03 +01001517 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001518 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001519 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001520 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001521 return -1;
1522 else
1523 return 0;
1524 }
1525 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001526 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001527 return 1;
1528 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001529 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001530 return -1;
1531 else
1532 return 0;
1533}
1534
1535/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001536 * returns the remaining time between tv1=now and event=tv2
1537 * if tv2 is passed, 0 is returned.
1538 * Returns TIME_ETERNITY if tv2 is eternity.
1539 */
1540static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1541 unsigned long ret;
1542
1543 if (tv_iseternity(tv2))
1544 return TIME_ETERNITY;
1545
1546 if (tv_cmp_ms(tv1, tv2) >= 0)
1547 return 0; /* event elapsed */
1548
1549 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1550 if (tv2->tv_usec > tv1->tv_usec)
1551 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1552 else
1553 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1554 return (unsigned long) ret;
1555}
1556
1557/*
willy tarreau0f7af912005-12-17 12:21:26 +01001558 * returns the first event between tv1 and tv2 into tvmin.
1559 * a zero tv is ignored. tvmin is returned.
1560 */
1561static inline struct timeval *tv_min(struct timeval *tvmin,
1562 struct timeval *tv1, struct timeval *tv2) {
1563
1564 if (tv_cmp2(tv1, tv2) <= 0)
1565 *tvmin = *tv1;
1566 else
1567 *tvmin = *tv2;
1568
1569 return tvmin;
1570}
1571
1572
1573
1574/***********************************************************/
1575/* fd management ***************************************/
1576/***********************************************************/
1577
1578
1579
willy tarreau5cbea6f2005-12-17 12:48:26 +01001580/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1581 * The file descriptor is also closed.
1582 */
willy tarreau0f7af912005-12-17 12:21:26 +01001583static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001584 FD_CLR(fd, StaticReadEvent);
1585 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001586#if defined(ENABLE_EPOLL)
1587 if (PrevReadEvent) {
1588 FD_CLR(fd, PrevReadEvent);
1589 FD_CLR(fd, PrevWriteEvent);
1590 }
1591#endif
1592
willy tarreau5cbea6f2005-12-17 12:48:26 +01001593 close(fd);
1594 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001595
1596 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1597 maxfd--;
1598}
1599
1600/* recomputes the maxfd limit from the fd */
1601static inline void fd_insert(int fd) {
1602 if (fd+1 > maxfd)
1603 maxfd = fd+1;
1604}
1605
1606/*************************************************************/
1607/* task management ***************************************/
1608/*************************************************************/
1609
willy tarreau5cbea6f2005-12-17 12:48:26 +01001610/* puts the task <t> in run queue <q>, and returns <t> */
1611static inline struct task *task_wakeup(struct task **q, struct task *t) {
1612 if (t->state == TASK_RUNNING)
1613 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001614 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001615 t->rqnext = *q;
1616 t->state = TASK_RUNNING;
1617 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001618 }
1619}
1620
willy tarreau5cbea6f2005-12-17 12:48:26 +01001621/* removes the task <t> from the queue <q>
1622 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001623 * set the run queue to point to the next one, and return it
1624 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001625static inline struct task *task_sleep(struct task **q, struct task *t) {
1626 if (t->state == TASK_RUNNING) {
1627 *q = t->rqnext;
1628 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001629 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001630 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001631}
1632
1633/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001634 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001635 * from the run queue. A pointer to the task itself is returned.
1636 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001637static inline struct task *task_delete(struct task *t) {
1638 t->prev->next = t->next;
1639 t->next->prev = t->prev;
1640 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001641}
1642
1643/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001644 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001645 */
1646static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001647 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001648}
1649
willy tarreau5cbea6f2005-12-17 12:48:26 +01001650/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001651 * may be only moved or left where it was, depending on its timing requirements.
1652 * <task> is returned.
1653 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001654struct task *task_queue(struct task *task) {
1655 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001656 struct task *start_from;
1657
1658 /* first, test if the task was already in a list */
1659 if (task->prev == NULL) {
1660 // start_from = list;
1661 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001662#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001663 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001664#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001665 /* insert the unlinked <task> into the list, searching back from the last entry */
1666 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1667 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001668#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001669 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001670#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001671 }
1672
1673 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1674 // start_from = start_from->next;
1675 // stats_tsk_nsrch++;
1676 // }
1677 }
1678 else if (task->prev == list ||
1679 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1680 start_from = task->next;
1681 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001682#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001683 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001684#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001685 return task; /* it's already in the right place */
1686 }
1687
willy tarreau750a4722005-12-17 13:21:24 +01001688#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001689 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001690#endif
1691
1692 /* if the task is not at the right place, there's little chance that
1693 * it has only shifted a bit, and it will nearly always be queued
1694 * at the end of the list because of constant timeouts
1695 * (observed in real case).
1696 */
1697#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1698 start_from = list->prev; /* assume we'll queue to the end of the list */
1699 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1700 start_from = start_from->prev;
1701#if STATTIME > 0
1702 stats_tsk_lsrch++;
1703#endif
1704 }
1705#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001706 /* insert the unlinked <task> into the list, searching after position <start_from> */
1707 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1708 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001709#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001710 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001711#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001712 }
willy tarreau750a4722005-12-17 13:21:24 +01001713#endif /* WE_REALLY_... */
1714
willy tarreau0f7af912005-12-17 12:21:26 +01001715 /* we need to unlink it now */
1716 task_delete(task);
1717 }
1718 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001719#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001720 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001721#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001722#ifdef LEFT_TO_TOP /* not very good */
1723 start_from = list;
1724 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1725 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001726#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001727 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001728#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001729 }
1730#else
1731 start_from = task->prev->prev; /* valid because of the previous test above */
1732 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1733 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001734#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001735 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001736#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001737 }
1738#endif
1739 /* we need to unlink it now */
1740 task_delete(task);
1741 }
1742 task->prev = start_from;
1743 task->next = start_from->next;
1744 task->next->prev = task;
1745 start_from->next = task;
1746 return task;
1747}
1748
1749
1750/*********************************************************************/
1751/* more specific functions ***************************************/
1752/*********************************************************************/
1753
1754/* some prototypes */
1755static int maintain_proxies(void);
1756
willy tarreaub952e1d2005-12-18 01:31:20 +01001757/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001758 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1759 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001760static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001761#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001762 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1763#else
willy tarreaua1598082005-12-17 13:08:06 +01001764#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001765 return getsockname(fd, (struct sockaddr *)sa, salen);
1766#else
1767 return -1;
1768#endif
1769#endif
1770}
1771
1772/*
1773 * frees the context associated to a session. It must have been removed first.
1774 */
1775static inline void session_free(struct session *s) {
1776 if (s->req)
1777 pool_free(buffer, s->req);
1778 if (s->rep)
1779 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001780
1781 if (s->rsp_cap != NULL) {
1782 struct cap_hdr *h;
1783 for (h = s->proxy->rsp_cap; h; h = h->next) {
1784 if (s->rsp_cap[h->index] != NULL)
1785 pool_free_to(h->pool, s->rsp_cap[h->index]);
1786 }
1787 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1788 }
1789 if (s->req_cap != NULL) {
1790 struct cap_hdr *h;
1791 for (h = s->proxy->req_cap; h; h = h->next) {
1792 if (s->req_cap[h->index] != NULL)
1793 pool_free_to(h->pool, s->req_cap[h->index]);
1794 }
1795 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1796 }
1797
willy tarreaua1598082005-12-17 13:08:06 +01001798 if (s->logs.uri)
1799 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001800 if (s->logs.cli_cookie)
1801 pool_free(capture, s->logs.cli_cookie);
1802 if (s->logs.srv_cookie)
1803 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001804
willy tarreau5cbea6f2005-12-17 12:48:26 +01001805 pool_free(session, s);
1806}
1807
willy tarreau0f7af912005-12-17 12:21:26 +01001808
1809/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01001810 * This function recounts the number of usable active and backup servers for
1811 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
1812 */
1813static inline void recount_servers(struct proxy *px) {
1814 struct server *srv;
1815
1816 px->srv_act = 0; px->srv_bck = 0;
1817 for (srv = px->srv; srv != NULL; srv = srv->next) {
1818 if (srv->state & SRV_RUNNING) {
1819 if (srv->state & SRV_BACKUP)
1820 px->srv_bck++;
1821 else
1822 px->srv_act++;
1823 }
1824 }
1825}
1826
1827/*
1828 * This function tries to find a running server for the proxy <px> following
1829 * the round-robin method. Depending on the number of active/backup servers,
1830 * it will either look for active servers, or for backup servers.
1831 * If any server is found, it will be returned and px->cursrv will be updated
1832 * to point to the next server. If no valid server is found, NULL is returned.
willy tarreau8337c6b2005-12-17 13:41:01 +01001833 */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001834static inline struct server *get_server_rr(struct proxy *px) {
1835 struct server *srv;
willy tarreau72e583d2006-03-23 11:27:02 +01001836 struct server *end;
willy tarreau8337c6b2005-12-17 13:41:01 +01001837
willy tarreau4c8c2b52006-03-24 19:36:41 +01001838 if (px->srv_act) {
1839 srv = px->cursrv;
willy tarreau72e583d2006-03-23 11:27:02 +01001840 if (srv == NULL)
1841 srv = px->srv;
1842 end = srv;
willy tarreau8337c6b2005-12-17 13:41:01 +01001843 do {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001844 if ((srv->state & (SRV_RUNNING | SRV_BACKUP)) == SRV_RUNNING) {
1845 px->cursrv = srv->next;
willy tarreau8337c6b2005-12-17 13:41:01 +01001846 return srv;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001847 }
1848
willy tarreau8337c6b2005-12-17 13:41:01 +01001849 srv = srv->next;
willy tarreau72e583d2006-03-23 11:27:02 +01001850 if (srv == NULL)
1851 srv = px->srv;
1852 } while (srv != end);
willy tarreau4c8c2b52006-03-24 19:36:41 +01001853 /* note that theorically we should not get there */
1854 }
Willy TARREAU3481c462006-03-01 22:37:57 +01001855
willy tarreau4c8c2b52006-03-24 19:36:41 +01001856 if (px->srv_bck) {
Willy TARREAU3481c462006-03-01 22:37:57 +01001857 /* By default, we look for the first backup server if all others are
1858 * DOWN. But in some cases, it may be desirable to load-balance across
1859 * all backup servers.
1860 */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001861 if (px->options & PR_O_USE_ALL_BK)
1862 srv = px->cursrv;
1863 else
1864 srv = px->srv;
1865
1866 if (srv == NULL)
Willy TARREAU3481c462006-03-01 22:37:57 +01001867 srv = px->srv;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001868 end = srv;
1869 do {
1870 if (srv->state & SRV_RUNNING) {
1871 px->cursrv = srv->next;
1872 return srv;
1873 }
1874 srv = srv->next;
1875 if (srv == NULL)
1876 srv = px->srv;
1877 } while (srv != end);
1878 /* note that theorically we should not get there */
1879 }
Willy TARREAU3481c462006-03-01 22:37:57 +01001880
willy tarreau4c8c2b52006-03-24 19:36:41 +01001881 /* if we get there, it means there are no available servers at all */
willy tarreau8337c6b2005-12-17 13:41:01 +01001882 return NULL;
1883}
1884
willy tarreau62084d42006-03-24 18:57:41 +01001885
1886/*
willy tarreau1a3442d2006-03-24 21:03:20 +01001887 * This function tries to find a running server for the proxy <px> following
1888 * the source hash method. Depending on the number of active/backup servers,
1889 * it will either look for active servers, or for backup servers.
1890 * If any server is found, it will be returned. If no valid server is found,
1891 * NULL is returned.
1892 */
1893static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
1894 struct server *srv;
1895
1896 if (px->srv_act) {
1897 unsigned int h, l;
1898
1899 l = h = 0;
1900 if (px->srv_act > 1) {
1901 while ((l + sizeof (int)) <= len) {
1902 h ^= ntohl(*(unsigned int *)(&addr[l]));
1903 l += sizeof (int);
1904 }
1905 h %= px->srv_act;
1906 }
1907
1908 for (srv = px->srv; srv; srv = srv->next) {
1909 if ((srv->state & (SRV_RUNNING | SRV_BACKUP)) == SRV_RUNNING) {
1910 if (!h)
1911 return srv;
1912 h--;
1913 }
1914 }
1915 /* note that theorically we should not get there */
1916 }
1917
1918 if (px->srv_bck) {
1919 unsigned int h, l;
1920
1921 /* By default, we look for the first backup server if all others are
1922 * DOWN. But in some cases, it may be desirable to load-balance across
1923 * all backup servers.
1924 */
1925 l = h = 0;
1926 if (px->srv_bck > 1 && px->options & PR_O_USE_ALL_BK) {
1927 while ((l + sizeof (int)) <= len) {
1928 h ^= ntohl(*(unsigned int *)(&addr[l]));
1929 l += sizeof (int);
1930 }
1931 h %= px->srv_bck;
1932 }
1933
1934 for (srv = px->srv; srv; srv = srv->next) {
1935 if (srv->state & SRV_RUNNING) {
1936 if (!h)
1937 return srv;
1938 h--;
1939 }
1940 }
1941 /* note that theorically we should not get there */
1942 }
1943
1944 /* if we get there, it means there are no available servers at all */
1945 return NULL;
1946}
1947
1948
1949/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001950 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01001951 * is set, or to the dispatch server if (s->direct) is 0.
1952 * It can return one of :
1953 * - SN_ERR_NONE if everything's OK
1954 * - SN_ERR_SRVTO if there are no more servers
1955 * - SN_ERR_SRVCL if the connection was refused by the server
1956 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1957 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1958 * - SN_ERR_INTERNAL for any other purely internal errors
1959 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01001960 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001961int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001962 int fd;
1963
willy tarreau12350152005-12-18 01:03:27 +01001964#ifdef DEBUG_FULL
1965 fprintf(stderr,"connect_server : s=%p\n",s);
1966#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001967
willy tarreaue39cd132005-12-17 13:00:18 +01001968 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001969 s->srv_addr = s->srv->addr;
1970 }
1971 else if (s->proxy->options & PR_O_BALANCE) {
willy tarreau1a3442d2006-03-24 21:03:20 +01001972 /* Ensure that srv will not be NULL */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001973 if (!s->proxy->srv_act && !s->proxy->srv_bck)
1974 return SN_ERR_SRVTO;
1975
willy tarreau5cbea6f2005-12-17 12:48:26 +01001976 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001977 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001978
willy tarreau4c8c2b52006-03-24 19:36:41 +01001979 srv = get_server_rr(s->proxy);
willy tarreau8337c6b2005-12-17 13:41:01 +01001980 s->srv_addr = srv->addr;
1981 s->srv = srv;
willy tarreau0f7af912005-12-17 12:21:26 +01001982 }
willy tarreau1a3442d2006-03-24 21:03:20 +01001983 else if (s->proxy->options & PR_O_BALANCE_SH) {
1984 struct server *srv;
1985 int len;
1986
1987 if (s->cli_addr.ss_family == AF_INET)
1988 len = 4;
1989 else if (s->cli_addr.ss_family == AF_INET6)
1990 len = 16;
1991 else /* unknown IP family */
1992 return SN_ERR_INTERNAL;
1993
1994 srv = get_server_sh(s->proxy,
1995 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
1996 len);
1997 s->srv_addr = srv->addr;
1998 s->srv = srv;
1999 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002000 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01002001 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002002 }
willy tarreaua1598082005-12-17 13:08:06 +01002003 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002004 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002005 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002006 }
2007 else if (s->proxy->options & PR_O_TRANSP) {
2008 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002009 socklen_t salen = sizeof(s->srv_addr);
2010
willy tarreau5cbea6f2005-12-17 12:48:26 +01002011 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2012 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002013 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002014 }
2015 }
willy tarreau0f7af912005-12-17 12:21:26 +01002016
willy tarreaua41a8b42005-12-17 14:02:24 +01002017 /* if this server remaps proxied ports, we'll use
2018 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01002019 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01002020 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002021 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01002022
willy tarreaub952e1d2005-12-18 01:31:20 +01002023 if (!(s->proxy->options & PR_O_TRANSP) ||
2024 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01002025 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2026 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
2027 }
2028
willy tarreau0f7af912005-12-17 12:21:26 +01002029 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002030 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002031
2032 if (errno == ENFILE)
2033 send_log(s->proxy, LOG_EMERG,
2034 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2035 s->proxy->id, maxfd);
2036 else if (errno == EMFILE)
2037 send_log(s->proxy, LOG_EMERG,
2038 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2039 s->proxy->id, maxfd);
2040 else if (errno == ENOBUFS || errno == ENOMEM)
2041 send_log(s->proxy, LOG_EMERG,
2042 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2043 s->proxy->id, maxfd);
2044 /* this is a resource error */
2045 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002046 }
2047
willy tarreau9fe663a2005-12-17 13:02:59 +01002048 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002049 /* do not log anything there, it's a normal condition when this option
2050 * is used to serialize connections to a server !
2051 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002052 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2053 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002054 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002055 }
2056
willy tarreau0f7af912005-12-17 12:21:26 +01002057 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2058 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002059 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002060 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002061 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002062 }
2063
willy tarreaub952e1d2005-12-18 01:31:20 +01002064 if (s->proxy->options & PR_O_TCP_SRV_KA)
2065 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2066
willy tarreau0174f312005-12-18 01:02:42 +01002067 /* allow specific binding :
2068 * - server-specific at first
2069 * - proxy-specific next
2070 */
2071 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2072 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2073 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2074 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2075 s->proxy->id, s->srv->id);
2076 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002077 send_log(s->proxy, LOG_EMERG,
2078 "Cannot bind to source address before connect() for server %s/%s.\n",
2079 s->proxy->id, s->srv->id);
2080 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002081 }
2082 }
2083 else if (s->proxy->options & PR_O_BIND_SRC) {
2084 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2085 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2086 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2087 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002088 send_log(s->proxy, LOG_EMERG,
2089 "Cannot bind to source address before connect() for server %s/%s.\n",
2090 s->proxy->id, s->srv->id);
2091 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002092 }
willy tarreaua1598082005-12-17 13:08:06 +01002093 }
2094
willy tarreaub1285d52005-12-18 01:20:14 +01002095 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2096 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2097
2098 if (errno == EAGAIN || errno == EADDRINUSE) {
2099 char *msg;
2100 if (errno == EAGAIN) /* no free ports left, try again later */
2101 msg = "no free ports";
2102 else
2103 msg = "local address already in use";
2104
2105 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002106 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002107 send_log(s->proxy, LOG_EMERG,
2108 "Connect() failed for server %s/%s: %s.\n",
2109 s->proxy->id, s->srv->id, msg);
2110 return SN_ERR_RESOURCE;
2111 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002112 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002113 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002114 return SN_ERR_SRVTO;
2115 } else {
2116 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002117 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002118 close(fd);
2119 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002120 }
2121 }
2122
willy tarreau5cbea6f2005-12-17 12:48:26 +01002123 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002124 fdtab[fd].read = &event_srv_read;
2125 fdtab[fd].write = &event_srv_write;
2126 fdtab[fd].state = FD_STCONN; /* connection in progress */
2127
2128 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002129#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2130 if (PrevReadEvent) {
2131 assert(!(FD_ISSET(fd, PrevReadEvent)));
2132 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2133 }
2134#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002135
2136 fd_insert(fd);
willy tarreauc1364612006-04-07 16:28:28 +02002137 s->srv->cur_sess++;
willy tarreau0f7af912005-12-17 12:21:26 +01002138
2139 if (s->proxy->contimeout)
2140 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2141 else
2142 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002143 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002144}
2145
2146/*
2147 * this function is called on a read event from a client socket.
2148 * It returns 0.
2149 */
2150int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002151 struct task *t = fdtab[fd].owner;
2152 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002153 struct buffer *b = s->req;
2154 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002155
willy tarreau12350152005-12-18 01:03:27 +01002156#ifdef DEBUG_FULL
2157 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2158#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002159
willy tarreau0f7af912005-12-17 12:21:26 +01002160 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002161#ifdef FILL_BUFFERS
2162 while (1)
2163#else
2164 do
2165#endif
2166 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002167 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2168 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002169 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002170 }
2171 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002172 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002173 }
2174 else {
2175 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002176 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2177 * since it means that the rewrite protection has been removed. This
2178 * implies that the if statement can be removed.
2179 */
2180 if (max > b->rlim - b->data)
2181 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002182 }
2183
2184 if (max == 0) { /* not anymore room to store data */
2185 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002186 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002187 }
2188
willy tarreau3242e862005-12-17 12:27:53 +01002189#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002190 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002191 int skerr;
2192 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002193
willy tarreau5cbea6f2005-12-17 12:48:26 +01002194 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2195 if (skerr)
2196 ret = -1;
2197 else
2198 ret = recv(fd, b->r, max, 0);
2199 }
willy tarreau3242e862005-12-17 12:27:53 +01002200#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002201 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002202#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002203 if (ret > 0) {
2204 b->r += ret;
2205 b->l += ret;
2206 s->res_cr = RES_DATA;
2207
2208 if (b->r == b->data + BUFSIZE) {
2209 b->r = b->data; /* wrap around the buffer */
2210 }
willy tarreaua1598082005-12-17 13:08:06 +01002211
2212 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002213 /* we hope to read more data or to get a close on next round */
2214 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002215 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002216 else if (ret == 0) {
2217 s->res_cr = RES_NULL;
2218 break;
2219 }
2220 else if (errno == EAGAIN) {/* ignore EAGAIN */
2221 break;
2222 }
2223 else {
2224 s->res_cr = RES_ERROR;
2225 fdtab[fd].state = FD_STERROR;
2226 break;
2227 }
2228 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002229#ifndef FILL_BUFFERS
2230 while (0);
2231#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002232 }
2233 else {
2234 s->res_cr = RES_ERROR;
2235 fdtab[fd].state = FD_STERROR;
2236 }
2237
willy tarreau5cbea6f2005-12-17 12:48:26 +01002238 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002239 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002240 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2241 else
2242 tv_eternity(&s->crexpire);
2243
2244 task_wakeup(&rq, t);
2245 }
willy tarreau0f7af912005-12-17 12:21:26 +01002246
willy tarreau0f7af912005-12-17 12:21:26 +01002247 return 0;
2248}
2249
2250
2251/*
2252 * this function is called on a read event from a server socket.
2253 * It returns 0.
2254 */
2255int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002256 struct task *t = fdtab[fd].owner;
2257 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002258 struct buffer *b = s->rep;
2259 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002260
willy tarreau12350152005-12-18 01:03:27 +01002261#ifdef DEBUG_FULL
2262 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2263#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002264
willy tarreau0f7af912005-12-17 12:21:26 +01002265 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002266#ifdef FILL_BUFFERS
2267 while (1)
2268#else
2269 do
2270#endif
2271 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002272 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2273 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002274 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002275 }
2276 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002277 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002278 }
2279 else {
2280 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002281 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2282 * since it means that the rewrite protection has been removed. This
2283 * implies that the if statement can be removed.
2284 */
2285 if (max > b->rlim - b->data)
2286 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002287 }
2288
2289 if (max == 0) { /* not anymore room to store data */
2290 FD_CLR(fd, StaticReadEvent);
2291 break;
2292 }
2293
willy tarreau3242e862005-12-17 12:27:53 +01002294#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002295 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002296 int skerr;
2297 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002298
willy tarreau5cbea6f2005-12-17 12:48:26 +01002299 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2300 if (skerr)
2301 ret = -1;
2302 else
2303 ret = recv(fd, b->r, max, 0);
2304 }
willy tarreau3242e862005-12-17 12:27:53 +01002305#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002306 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002307#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002308 if (ret > 0) {
2309 b->r += ret;
2310 b->l += ret;
2311 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002312
willy tarreau5cbea6f2005-12-17 12:48:26 +01002313 if (b->r == b->data + BUFSIZE) {
2314 b->r = b->data; /* wrap around the buffer */
2315 }
willy tarreaua1598082005-12-17 13:08:06 +01002316
2317 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002318 /* we hope to read more data or to get a close on next round */
2319 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002320 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002321 else if (ret == 0) {
2322 s->res_sr = RES_NULL;
2323 break;
2324 }
2325 else if (errno == EAGAIN) {/* ignore EAGAIN */
2326 break;
2327 }
2328 else {
2329 s->res_sr = RES_ERROR;
2330 fdtab[fd].state = FD_STERROR;
2331 break;
2332 }
2333 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002334#ifndef FILL_BUFFERS
2335 while (0);
2336#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002337 }
2338 else {
2339 s->res_sr = RES_ERROR;
2340 fdtab[fd].state = FD_STERROR;
2341 }
2342
willy tarreau5cbea6f2005-12-17 12:48:26 +01002343 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002344 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002345 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2346 else
2347 tv_eternity(&s->srexpire);
2348
2349 task_wakeup(&rq, t);
2350 }
willy tarreau0f7af912005-12-17 12:21:26 +01002351
willy tarreau0f7af912005-12-17 12:21:26 +01002352 return 0;
2353}
2354
2355/*
2356 * this function is called on a write event from a client socket.
2357 * It returns 0.
2358 */
2359int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002360 struct task *t = fdtab[fd].owner;
2361 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002362 struct buffer *b = s->rep;
2363 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002364
willy tarreau12350152005-12-18 01:03:27 +01002365#ifdef DEBUG_FULL
2366 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2367#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002368
2369 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002370 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002371 // max = BUFSIZE; BUG !!!!
2372 max = 0;
2373 }
2374 else if (b->r > b->w) {
2375 max = b->r - b->w;
2376 }
2377 else
2378 max = b->data + BUFSIZE - b->w;
2379
willy tarreau0f7af912005-12-17 12:21:26 +01002380 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002381 if (max == 0) {
2382 s->res_cw = RES_NULL;
2383 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002384 tv_eternity(&s->cwexpire);
2385 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002386 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002387 }
2388
willy tarreau3242e862005-12-17 12:27:53 +01002389#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002390 {
2391 int skerr;
2392 socklen_t lskerr = sizeof(skerr);
2393
2394 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2395 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002396 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002397 else
willy tarreau3242e862005-12-17 12:27:53 +01002398 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002399 }
willy tarreau3242e862005-12-17 12:27:53 +01002400#else
willy tarreau0f7af912005-12-17 12:21:26 +01002401 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002402#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002403
2404 if (ret > 0) {
2405 b->l -= ret;
2406 b->w += ret;
2407
2408 s->res_cw = RES_DATA;
2409
2410 if (b->w == b->data + BUFSIZE) {
2411 b->w = b->data; /* wrap around the buffer */
2412 }
2413 }
2414 else if (ret == 0) {
2415 /* nothing written, just make as if we were never called */
2416// s->res_cw = RES_NULL;
2417 return 0;
2418 }
2419 else if (errno == EAGAIN) /* ignore EAGAIN */
2420 return 0;
2421 else {
2422 s->res_cw = RES_ERROR;
2423 fdtab[fd].state = FD_STERROR;
2424 }
2425 }
2426 else {
2427 s->res_cw = RES_ERROR;
2428 fdtab[fd].state = FD_STERROR;
2429 }
2430
willy tarreaub1ff9db2005-12-17 13:51:03 +01002431 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002432 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002433 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2434 s->crexpire = s->cwexpire;
2435 }
willy tarreau0f7af912005-12-17 12:21:26 +01002436 else
2437 tv_eternity(&s->cwexpire);
2438
willy tarreau5cbea6f2005-12-17 12:48:26 +01002439 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002440 return 0;
2441}
2442
2443
2444/*
2445 * this function is called on a write event from a server socket.
2446 * It returns 0.
2447 */
2448int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002449 struct task *t = fdtab[fd].owner;
2450 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002451 struct buffer *b = s->req;
2452 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002453
willy tarreau12350152005-12-18 01:03:27 +01002454#ifdef DEBUG_FULL
2455 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2456#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002457
2458 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002459 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002460 // max = BUFSIZE; BUG !!!!
2461 max = 0;
2462 }
2463 else if (b->r > b->w) {
2464 max = b->r - b->w;
2465 }
2466 else
2467 max = b->data + BUFSIZE - b->w;
2468
willy tarreau0f7af912005-12-17 12:21:26 +01002469 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002470 if (max == 0) {
2471 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002472 if (s->srv_state == SV_STCONN) {
2473 int skerr;
2474 socklen_t lskerr = sizeof(skerr);
2475 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2476 if (skerr) {
2477 s->res_sw = RES_ERROR;
2478 fdtab[fd].state = FD_STERROR;
2479 task_wakeup(&rq, t);
2480 tv_eternity(&s->swexpire);
2481 FD_CLR(fd, StaticWriteEvent);
2482 return 0;
2483 }
2484 }
2485
willy tarreau0f7af912005-12-17 12:21:26 +01002486 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002487 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002488 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002489 tv_eternity(&s->swexpire);
2490 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002491 return 0;
2492 }
2493
willy tarreau3242e862005-12-17 12:27:53 +01002494#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002495 {
2496 int skerr;
2497 socklen_t lskerr = sizeof(skerr);
2498 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2499 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002500 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002501 else
willy tarreau3242e862005-12-17 12:27:53 +01002502 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002503 }
willy tarreau3242e862005-12-17 12:27:53 +01002504#else
willy tarreau0f7af912005-12-17 12:21:26 +01002505 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002506#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002507 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002508 if (ret > 0) {
2509 b->l -= ret;
2510 b->w += ret;
2511
2512 s->res_sw = RES_DATA;
2513
2514 if (b->w == b->data + BUFSIZE) {
2515 b->w = b->data; /* wrap around the buffer */
2516 }
2517 }
2518 else if (ret == 0) {
2519 /* nothing written, just make as if we were never called */
2520 // s->res_sw = RES_NULL;
2521 return 0;
2522 }
2523 else if (errno == EAGAIN) /* ignore EAGAIN */
2524 return 0;
2525 else {
2526 s->res_sw = RES_ERROR;
2527 fdtab[fd].state = FD_STERROR;
2528 }
2529 }
2530 else {
2531 s->res_sw = RES_ERROR;
2532 fdtab[fd].state = FD_STERROR;
2533 }
2534
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002535 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2536 * otherwise it could loop indefinitely !
2537 */
2538 if (s->srv_state != SV_STCONN) {
2539 if (s->proxy->srvtimeout) {
2540 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
2541 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2542 s->srexpire = s->swexpire;
2543 }
2544 else
2545 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002546 }
willy tarreau0f7af912005-12-17 12:21:26 +01002547
willy tarreau5cbea6f2005-12-17 12:48:26 +01002548 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002549 return 0;
2550}
2551
2552
2553/*
willy tarreaue39cd132005-12-17 13:00:18 +01002554 * returns a message to the client ; the connection is shut down for read,
2555 * and the request is cleared so that no server connection can be initiated.
2556 * The client must be in a valid state for this (HEADER, DATA ...).
2557 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002558 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002559 */
2560void client_retnclose(struct session *s, int len, const char *msg) {
2561 FD_CLR(s->cli_fd, StaticReadEvent);
2562 FD_SET(s->cli_fd, StaticWriteEvent);
2563 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002564 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002565 shutdown(s->cli_fd, SHUT_RD);
2566 s->cli_state = CL_STSHUTR;
2567 strcpy(s->rep->data, msg);
2568 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002569 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002570 s->rep->r += len;
2571 s->req->l = 0;
2572}
2573
2574
2575/*
2576 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002577 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002578 */
2579void client_return(struct session *s, int len, const char *msg) {
2580 strcpy(s->rep->data, msg);
2581 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002582 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002583 s->rep->r += len;
2584 s->req->l = 0;
2585}
2586
willy tarreau9fe663a2005-12-17 13:02:59 +01002587/*
2588 * send a log for the session when we have enough info about it
2589 */
2590void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002591 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002592 struct proxy *p = s->proxy;
2593 int log;
2594 char *uri;
2595 char *pxid;
2596 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002597 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002598
2599 /* This is a first attempt at a better logging system.
2600 * For now, we rely on send_log() to provide the date, although it obviously
2601 * is the date of the log and not of the request, and most fields are not
2602 * computed.
2603 */
2604
willy tarreaua1598082005-12-17 13:08:06 +01002605 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002606
willy tarreau8a86dbf2005-12-18 00:45:59 +01002607 if (s->cli_addr.ss_family == AF_INET)
2608 inet_ntop(AF_INET,
2609 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2610 pn, sizeof(pn));
2611 else
2612 inet_ntop(AF_INET6,
2613 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2614 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002615
willy tarreauc1cae632005-12-17 14:12:23 +01002616 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002617 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002618 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002619
willy tarreauc1cae632005-12-17 14:12:23 +01002620 tm = localtime(&s->logs.tv_accept.tv_sec);
2621 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002622 char tmpline[MAX_SYSLOG_LEN], *h;
2623 int hdr;
2624
2625 h = tmpline;
2626 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2627 *(h++) = ' ';
2628 *(h++) = '{';
2629 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2630 if (hdr)
2631 *(h++) = '|';
2632 if (s->req_cap[hdr] != NULL)
2633 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2634 }
2635 *(h++) = '}';
2636 }
2637
2638 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2639 *(h++) = ' ';
2640 *(h++) = '{';
2641 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2642 if (hdr)
2643 *(h++) = '|';
2644 if (s->rsp_cap[hdr] != NULL)
2645 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2646 }
2647 *(h++) = '}';
2648 }
2649
2650 if (h < tmpline + sizeof(tmpline) - 4) {
2651 *(h++) = ' ';
2652 *(h++) = '"';
2653 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2654 *(h++) = '"';
2655 }
2656 *h = '\0';
2657
willy tarreauc1364612006-04-07 16:28:28 +02002658 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%s%d %d %s%lld %s %s %c%c%c%c %d/%d/%d%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002659 pn,
2660 (s->cli_addr.ss_family == AF_INET) ?
2661 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2662 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002663 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2664 tm->tm_hour, tm->tm_min, tm->tm_sec,
2665 pxid, srv,
2666 s->logs.t_request,
2667 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2668 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002669 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2670 s->logs.status,
2671 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002672 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2673 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002674 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2675 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2676 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2677 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreauc1364612006-04-07 16:28:28 +02002678 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002679 }
2680 else {
willy tarreauc1364612006-04-07 16:28:28 +02002681 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c %d/%d/%d\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002682 pn,
2683 (s->cli_addr.ss_family == AF_INET) ?
2684 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2685 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002686 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2687 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002688 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002689 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002690 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2691 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002692 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002693 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreauc1364612006-04-07 16:28:28 +02002694 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002695 }
2696
2697 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002698}
2699
willy tarreaue39cd132005-12-17 13:00:18 +01002700
2701/*
willy tarreau0f7af912005-12-17 12:21:26 +01002702 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002703 * to an accept. It tries to accept as many connections as possible.
2704 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002705 */
2706int event_accept(int fd) {
2707 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002708 struct session *s;
2709 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002710 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01002711 int max_accept;
2712
2713 if (global.nbproc > 1)
2714 max_accept = 8; /* let other processes catch some connections too */
2715 else
2716 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01002717
willy tarreauc2becdc2006-03-19 19:36:48 +01002718 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002719 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002720 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002721
willy tarreaub1285d52005-12-18 01:20:14 +01002722 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2723 switch (errno) {
2724 case EAGAIN:
2725 case EINTR:
2726 case ECONNABORTED:
2727 return 0; /* nothing more to accept */
2728 case ENFILE:
2729 send_log(p, LOG_EMERG,
2730 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2731 p->id, maxfd);
2732 return 0;
2733 case EMFILE:
2734 send_log(p, LOG_EMERG,
2735 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2736 p->id, maxfd);
2737 return 0;
2738 case ENOBUFS:
2739 case ENOMEM:
2740 send_log(p, LOG_EMERG,
2741 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2742 p->id, maxfd);
2743 return 0;
2744 default:
2745 return 0;
2746 }
2747 }
willy tarreau0f7af912005-12-17 12:21:26 +01002748
willy tarreau5cbea6f2005-12-17 12:48:26 +01002749 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2750 Alert("out of memory in event_accept().\n");
2751 FD_CLR(fd, StaticReadEvent);
2752 p->state = PR_STIDLE;
2753 close(cfd);
2754 return 0;
2755 }
willy tarreau0f7af912005-12-17 12:21:26 +01002756
willy tarreaub1285d52005-12-18 01:20:14 +01002757 /* if this session comes from a known monitoring system, we want to ignore
2758 * it as soon as possible, which means closing it immediately for TCP.
2759 */
2760 s->flags = 0;
2761 if (addr.ss_family == AF_INET &&
2762 p->mon_mask.s_addr &&
2763 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2764 if (p->mode == PR_MODE_TCP) {
2765 close(cfd);
2766 pool_free(session, s);
2767 continue;
2768 }
2769 s->flags |= SN_MONITOR;
2770 }
2771
willy tarreau5cbea6f2005-12-17 12:48:26 +01002772 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2773 Alert("out of memory in event_accept().\n");
2774 FD_CLR(fd, StaticReadEvent);
2775 p->state = PR_STIDLE;
2776 close(cfd);
2777 pool_free(session, s);
2778 return 0;
2779 }
willy tarreau0f7af912005-12-17 12:21:26 +01002780
willy tarreau5cbea6f2005-12-17 12:48:26 +01002781 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002782 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002783 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2784 close(cfd);
2785 pool_free(task, t);
2786 pool_free(session, s);
2787 return 0;
2788 }
willy tarreau0f7af912005-12-17 12:21:26 +01002789
willy tarreau5cbea6f2005-12-17 12:48:26 +01002790 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2791 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2792 (char *) &one, sizeof(one)) == -1)) {
2793 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2794 close(cfd);
2795 pool_free(task, t);
2796 pool_free(session, s);
2797 return 0;
2798 }
willy tarreau0f7af912005-12-17 12:21:26 +01002799
willy tarreaub952e1d2005-12-18 01:31:20 +01002800 if (p->options & PR_O_TCP_CLI_KA)
2801 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2802
willy tarreau9fe663a2005-12-17 13:02:59 +01002803 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2804 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2805 t->state = TASK_IDLE;
2806 t->process = process_session;
2807 t->context = s;
2808
2809 s->task = t;
2810 s->proxy = p;
2811 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2812 s->srv_state = SV_STIDLE;
2813 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002814
willy tarreau9fe663a2005-12-17 13:02:59 +01002815 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2816 s->cli_fd = cfd;
2817 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002818 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002819 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002820
willy tarreaub1285d52005-12-18 01:20:14 +01002821 if (s->flags & SN_MONITOR)
2822 s->logs.logwait = 0;
2823 else
2824 s->logs.logwait = p->to_log;
2825
willy tarreaua1598082005-12-17 13:08:06 +01002826 s->logs.tv_accept = now;
2827 s->logs.t_request = -1;
2828 s->logs.t_connect = -1;
2829 s->logs.t_data = -1;
2830 s->logs.t_close = 0;
2831 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002832 s->logs.cli_cookie = NULL;
2833 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002834 s->logs.status = -1;
2835 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002836
willy tarreau2f6ba652005-12-17 13:57:42 +01002837 s->uniq_id = totalconn;
2838
willy tarreau4302f492005-12-18 01:00:37 +01002839 if (p->nb_req_cap > 0) {
2840 if ((s->req_cap =
2841 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2842 == NULL) { /* no memory */
2843 close(cfd); /* nothing can be done for this fd without memory */
2844 pool_free(task, t);
2845 pool_free(session, s);
2846 return 0;
2847 }
2848 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2849 }
2850 else
2851 s->req_cap = NULL;
2852
2853 if (p->nb_rsp_cap > 0) {
2854 if ((s->rsp_cap =
2855 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2856 == NULL) { /* no memory */
2857 if (s->req_cap != NULL)
2858 pool_free_to(p->req_cap_pool, s->req_cap);
2859 close(cfd); /* nothing can be done for this fd without memory */
2860 pool_free(task, t);
2861 pool_free(session, s);
2862 return 0;
2863 }
2864 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2865 }
2866 else
2867 s->rsp_cap = NULL;
2868
willy tarreau5cbea6f2005-12-17 12:48:26 +01002869 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2870 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002871 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002872 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002873
willy tarreau8a86dbf2005-12-18 00:45:59 +01002874 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002875 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002876 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002877 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002878
willy tarreau9fe663a2005-12-17 13:02:59 +01002879 if (p->to_log) {
2880 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002881 if (s->logs.logwait & LW_CLIP)
2882 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002883 sess_log(s);
2884 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002885 else if (s->cli_addr.ss_family == AF_INET) {
2886 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2887 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2888 sn, sizeof(sn)) &&
2889 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2890 pn, sizeof(pn))) {
2891 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2892 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2893 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2894 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2895 }
2896 }
2897 else {
2898 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2899 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2900 sn, sizeof(sn)) &&
2901 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2902 pn, sizeof(pn))) {
2903 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2904 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2905 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2906 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2907 }
2908 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002909 }
willy tarreau0f7af912005-12-17 12:21:26 +01002910
willy tarreau982249e2005-12-18 00:57:06 +01002911 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002912 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002913 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002914 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002915 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002916 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002917 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002918 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002919
willy tarreau8a86dbf2005-12-18 00:45:59 +01002920 if (s->cli_addr.ss_family == AF_INET) {
2921 char pn[INET_ADDRSTRLEN];
2922 inet_ntop(AF_INET,
2923 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2924 pn, sizeof(pn));
2925
2926 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2927 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2928 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2929 }
2930 else {
2931 char pn[INET6_ADDRSTRLEN];
2932 inet_ntop(AF_INET6,
2933 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2934 pn, sizeof(pn));
2935
2936 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2937 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2938 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2939 }
2940
willy tarreauef900ab2005-12-17 12:52:52 +01002941 write(1, trash, len);
2942 }
willy tarreau0f7af912005-12-17 12:21:26 +01002943
willy tarreau5cbea6f2005-12-17 12:48:26 +01002944 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002945 if (s->rsp_cap != NULL)
2946 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2947 if (s->req_cap != NULL)
2948 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002949 close(cfd); /* nothing can be done for this fd without memory */
2950 pool_free(task, t);
2951 pool_free(session, s);
2952 return 0;
2953 }
willy tarreau4302f492005-12-18 01:00:37 +01002954
willy tarreau5cbea6f2005-12-17 12:48:26 +01002955 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002956 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002957 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2958 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002959 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002960 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002961
willy tarreau5cbea6f2005-12-17 12:48:26 +01002962 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2963 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002964 if (s->rsp_cap != NULL)
2965 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2966 if (s->req_cap != NULL)
2967 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002968 close(cfd); /* nothing can be done for this fd without memory */
2969 pool_free(task, t);
2970 pool_free(session, s);
2971 return 0;
2972 }
2973 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002974 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002975 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 +01002976
willy tarreau5cbea6f2005-12-17 12:48:26 +01002977 fdtab[cfd].read = &event_cli_read;
2978 fdtab[cfd].write = &event_cli_write;
2979 fdtab[cfd].owner = t;
2980 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002981
willy tarreaub1285d52005-12-18 01:20:14 +01002982 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2983 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2984 /* Either we got a request from a monitoring system on an HTTP instance,
2985 * or we're in health check mode with the 'httpchk' option enabled. In
2986 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2987 */
2988 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2989 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2990 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002991 }
2992 else {
2993 FD_SET(cfd, StaticReadEvent);
2994 }
2995
willy tarreaub952e1d2005-12-18 01:31:20 +01002996#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2997 if (PrevReadEvent) {
2998 assert(!(FD_ISSET(cfd, PrevReadEvent)));
2999 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3000 }
3001#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003002 fd_insert(cfd);
3003
3004 tv_eternity(&s->cnexpire);
3005 tv_eternity(&s->srexpire);
3006 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003007 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003008 tv_eternity(&s->cwexpire);
3009
willy tarreaub1285d52005-12-18 01:20:14 +01003010 if (s->proxy->clitimeout) {
3011 if (FD_ISSET(cfd, StaticReadEvent))
3012 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3013 if (FD_ISSET(cfd, StaticWriteEvent))
3014 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3015 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003016
willy tarreaub1285d52005-12-18 01:20:14 +01003017 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003018
3019 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003020
3021 if (p->mode != PR_MODE_HEALTH)
3022 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003023
3024 p->nbconn++;
3025 actconn++;
3026 totalconn++;
3027
willy tarreaub952e1d2005-12-18 01:31:20 +01003028 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003029 } /* end of while (p->nbconn < p->maxconn) */
3030 return 0;
3031}
willy tarreau0f7af912005-12-17 12:21:26 +01003032
willy tarreau0f7af912005-12-17 12:21:26 +01003033
willy tarreau5cbea6f2005-12-17 12:48:26 +01003034/*
3035 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003036 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3037 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003038 * or -1 if an error occured.
3039 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003040int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003041 struct task *t = fdtab[fd].owner;
3042 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003043 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003044 socklen_t lskerr = sizeof(skerr);
3045
willy tarreau05be12b2006-03-19 19:35:00 +01003046 skerr = 1;
3047 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3048 || (skerr != 0)) {
3049 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003050 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003051 fdtab[fd].state = FD_STERROR;
3052 FD_CLR(fd, StaticWriteEvent);
3053 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003054 else if (s->result != -1) {
3055 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003056 if (s->proxy->options & PR_O_HTTP_CHK) {
3057 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003058 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003059 * so we'll send the request, and won't wake the checker up now.
3060 */
3061#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003062 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003063#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003064 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003065#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003066 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003067 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3068 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3069 return 0;
3070 }
willy tarreau05be12b2006-03-19 19:35:00 +01003071 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003072 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003073 FD_CLR(fd, StaticWriteEvent);
3074 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003075 }
3076 else {
3077 /* good TCP connection is enough */
3078 s->result = 1;
3079 }
3080 }
3081
3082 task_wakeup(&rq, t);
3083 return 0;
3084}
3085
willy tarreau0f7af912005-12-17 12:21:26 +01003086
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003087/*
3088 * This function is used only for server health-checks. It handles
3089 * the server's reply to an HTTP request. It returns 1 if the server replies
3090 * 2xx or 3xx (valid responses), or -1 in other cases.
3091 */
3092int event_srv_chk_r(int fd) {
3093 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003094 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003095 struct task *t = fdtab[fd].owner;
3096 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003097 int skerr;
3098 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003099
willy tarreaua4a583a2005-12-18 01:39:19 +01003100 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003101
willy tarreau05be12b2006-03-19 19:35:00 +01003102 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3103 if (!skerr) {
3104#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003105 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003106#else
willy tarreau05be12b2006-03-19 19:35:00 +01003107 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3108 * but the connection was closed on the remote end. Fortunately, recv still
3109 * works correctly and we don't need to do the getsockopt() on linux.
3110 */
3111 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003112#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003113
3114 if ((len >= sizeof("HTTP/1.0 000")) &&
3115 !memcmp(reply, "HTTP/1.", 7) &&
3116 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3117 result = 1;
3118 }
3119
3120 if (result == -1)
3121 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003122
3123 if (s->result != -1)
3124 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003125
3126 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003127 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003128 return 0;
3129}
3130
3131
3132/*
3133 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3134 * and moves <end> just after the end of <str>.
3135 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3136 * the shift value (positive or negative) is returned.
3137 * If there's no space left, the move is not done.
3138 *
3139 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003140int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003141 int delta;
3142 int len;
3143
3144 len = strlen(str);
3145 delta = len - (end - pos);
3146
3147 if (delta + b->r >= b->data + BUFSIZE)
3148 return 0; /* no space left */
3149
3150 /* first, protect the end of the buffer */
3151 memmove(end + delta, end, b->data + b->l - end);
3152
3153 /* now, copy str over pos */
3154 memcpy(pos, str,len);
3155
willy tarreau5cbea6f2005-12-17 12:48:26 +01003156 /* we only move data after the displaced zone */
3157 if (b->r > pos) b->r += delta;
3158 if (b->w > pos) b->w += delta;
3159 if (b->h > pos) b->h += delta;
3160 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003161 b->l += delta;
3162
3163 return delta;
3164}
3165
willy tarreau8337c6b2005-12-17 13:41:01 +01003166/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003167 * len is 0.
3168 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003169int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003170 int delta;
3171
3172 delta = len - (end - pos);
3173
3174 if (delta + b->r >= b->data + BUFSIZE)
3175 return 0; /* no space left */
3176
Willy TARREAUe78ae262006-01-08 01:24:12 +01003177 if (b->data + b->l < end)
3178 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3179 return 0;
3180
willy tarreau0f7af912005-12-17 12:21:26 +01003181 /* first, protect the end of the buffer */
3182 memmove(end + delta, end, b->data + b->l - end);
3183
3184 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003185 if (len)
3186 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003187
willy tarreau5cbea6f2005-12-17 12:48:26 +01003188 /* we only move data after the displaced zone */
3189 if (b->r > pos) b->r += delta;
3190 if (b->w > pos) b->w += delta;
3191 if (b->h > pos) b->h += delta;
3192 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003193 b->l += delta;
3194
3195 return delta;
3196}
3197
3198
3199int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3200 char *old_dst = dst;
3201
3202 while (*str) {
3203 if (*str == '\\') {
3204 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003205 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003206 int len, num;
3207
3208 num = *str - '0';
3209 str++;
3210
willy tarreau8a86dbf2005-12-18 00:45:59 +01003211 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003212 len = matches[num].rm_eo - matches[num].rm_so;
3213 memcpy(dst, src + matches[num].rm_so, len);
3214 dst += len;
3215 }
3216
3217 }
3218 else if (*str == 'x') {
3219 unsigned char hex1, hex2;
3220 str++;
3221
willy tarreauc1f47532005-12-18 01:08:26 +01003222 hex1 = toupper(*str++) - '0';
3223 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003224
3225 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3226 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3227 *dst++ = (hex1<<4) + hex2;
3228 }
3229 else
3230 *dst++ = *str++;
3231 }
3232 else
3233 *dst++ = *str++;
3234 }
3235 *dst = 0;
3236 return dst - old_dst;
3237}
3238
willy tarreauc1f47532005-12-18 01:08:26 +01003239static int ishex(char s)
3240{
3241 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3242}
3243
3244/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3245char *check_replace_string(char *str)
3246{
3247 char *err = NULL;
3248 while (*str) {
3249 if (*str == '\\') {
3250 err = str; /* in case of a backslash, we return the pointer to it */
3251 str++;
3252 if (!*str)
3253 return err;
3254 else if (isdigit((int)*str))
3255 err = NULL;
3256 else if (*str == 'x') {
3257 str++;
3258 if (!ishex(*str))
3259 return err;
3260 str++;
3261 if (!ishex(*str))
3262 return err;
3263 err = NULL;
3264 }
3265 else {
3266 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3267 err = NULL;
3268 }
3269 }
3270 str++;
3271 }
3272 return err;
3273}
3274
3275
willy tarreau9fe663a2005-12-17 13:02:59 +01003276
willy tarreau0f7af912005-12-17 12:21:26 +01003277/*
3278 * manages the client FSM and its socket. BTW, it also tries to handle the
3279 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3280 * 0 else.
3281 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003282int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003283 int s = t->srv_state;
3284 int c = t->cli_state;
3285 struct buffer *req = t->req;
3286 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003287 int method_checked = 0;
3288 appsess *asession_temp = NULL;
3289 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003290
willy tarreau750a4722005-12-17 13:21:24 +01003291#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003292 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3293 cli_stnames[c], srv_stnames[s],
3294 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3295 t->crexpire.tv_sec, t->crexpire.tv_usec,
3296 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003297#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003298 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3299 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3300 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3301 //);
3302 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003303 /* now parse the partial (or complete) headers */
3304 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3305 char *ptr;
3306 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003307 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003308
willy tarreau5cbea6f2005-12-17 12:48:26 +01003309 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003310
willy tarreau0f7af912005-12-17 12:21:26 +01003311 /* look for the end of the current header */
3312 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3313 ptr++;
3314
willy tarreau5cbea6f2005-12-17 12:48:26 +01003315 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003316 int line, len;
3317 /* we can only get here after an end of headers */
3318 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003319
willy tarreaue39cd132005-12-17 13:00:18 +01003320 if (t->flags & SN_CLDENY) {
3321 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003322 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003323 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003324 if (!(t->flags & SN_ERR_MASK))
3325 t->flags |= SN_ERR_PRXCOND;
3326 if (!(t->flags & SN_FINST_MASK))
3327 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003328 return 1;
3329 }
3330
willy tarreau5cbea6f2005-12-17 12:48:26 +01003331 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003332 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3333 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003334 }
willy tarreau0f7af912005-12-17 12:21:26 +01003335
willy tarreau9fe663a2005-12-17 13:02:59 +01003336 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003337 if (t->cli_addr.ss_family == AF_INET) {
3338 unsigned char *pn;
3339 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3340 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3341 pn[0], pn[1], pn[2], pn[3]);
3342 buffer_replace2(req, req->h, req->h, trash, len);
3343 }
3344 else if (t->cli_addr.ss_family == AF_INET6) {
3345 char pn[INET6_ADDRSTRLEN];
3346 inet_ntop(AF_INET6,
3347 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3348 pn, sizeof(pn));
3349 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3350 buffer_replace2(req, req->h, req->h, trash, len);
3351 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003352 }
3353
willy tarreau25c4ea52005-12-18 00:49:49 +01003354 /* add a "connection: close" line if needed */
3355 if (t->proxy->options & PR_O_HTTP_CLOSE)
3356 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3357
willy tarreau982249e2005-12-18 00:57:06 +01003358 if (!memcmp(req->data, "POST ", 5)) {
3359 /* this is a POST request, which is not cacheable by default */
3360 t->flags |= SN_POST;
3361 }
willy tarreaucd878942005-12-17 13:27:43 +01003362
willy tarreau5cbea6f2005-12-17 12:48:26 +01003363 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003364 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003365
willy tarreau750a4722005-12-17 13:21:24 +01003366 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003367 /* FIXME: we'll set the client in a wait state while we try to
3368 * connect to the server. Is this really needed ? wouldn't it be
3369 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003370 //FD_CLR(t->cli_fd, StaticReadEvent);
3371 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003372
3373 /* FIXME: if we break here (as up to 1.1.23), having the client
3374 * shutdown its connection can lead to an abort further.
3375 * it's better to either return 1 or even jump directly to the
3376 * data state which will save one schedule.
3377 */
3378 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003379
3380 if (!t->proxy->clitimeout ||
3381 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3382 /* If the client has no timeout, or if the server is not ready yet,
3383 * and we know for sure that it can expire, then it's cleaner to
3384 * disable the timeout on the client side so that too low values
3385 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003386 *
3387 * FIXME-20050705: the server needs a way to re-enable this time-out
3388 * when it switches its state, otherwise a client can stay connected
3389 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003390 */
3391 tv_eternity(&t->crexpire);
3392
willy tarreau197e8ec2005-12-17 14:10:59 +01003393 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003394 }
willy tarreau0f7af912005-12-17 12:21:26 +01003395
Willy TARREAU13032e72006-03-12 17:31:45 +01003396 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3397 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003398 /* this is a partial header, let's wait for more to come */
3399 req->lr = ptr;
3400 break;
3401 }
willy tarreau0f7af912005-12-17 12:21:26 +01003402
willy tarreau5cbea6f2005-12-17 12:48:26 +01003403 /* now we know that *ptr is either \r or \n,
3404 * and that there are at least 1 char after it.
3405 */
3406 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3407 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3408 else
3409 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003410
willy tarreau5cbea6f2005-12-17 12:48:26 +01003411 /*
3412 * now we know that we have a full header ; we can do whatever
3413 * we want with these pointers :
3414 * req->h = beginning of header
3415 * ptr = end of header (first \r or \n)
3416 * req->lr = beginning of next line (next rep->h)
3417 * req->r = end of data (not used at this stage)
3418 */
willy tarreau0f7af912005-12-17 12:21:26 +01003419
willy tarreau12350152005-12-18 01:03:27 +01003420 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3421 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3422 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3423
3424 /* skip ; */
3425 request_line++;
3426
3427 /* look if we have a jsessionid */
3428
3429 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3430
3431 /* skip jsessionid= */
3432 request_line += t->proxy->appsession_name_len + 1;
3433
3434 /* First try if we allready have an appsession */
3435 asession_temp = &local_asession;
3436
3437 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3438 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3439 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3440 return 0;
3441 }
3442
3443 /* Copy the sessionid */
3444 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3445 asession_temp->sessid[t->proxy->appsession_len] = 0;
3446 asession_temp->serverid = NULL;
3447
3448 /* only do insert, if lookup fails */
3449 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3450 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3451 Alert("Not enough memory process_cli():asession:calloc().\n");
3452 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3453 return 0;
3454 }
3455 asession_temp->sessid = local_asession.sessid;
3456 asession_temp->serverid = local_asession.serverid;
3457 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003458 } /* end if (chtbl_lookup()) */
3459 else {
willy tarreau12350152005-12-18 01:03:27 +01003460 /*free wasted memory;*/
3461 pool_free_to(apools.sessid, local_asession.sessid);
3462 }
3463
3464 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3465 asession_temp->request_count++;
3466
3467#if defined(DEBUG_HASH)
3468 print_table(&(t->proxy->htbl_proxy));
3469#endif
3470
3471 if (asession_temp->serverid == NULL) {
3472 Alert("Found Application Session without matching server.\n");
3473 } else {
3474 struct server *srv = t->proxy->srv;
3475 while (srv) {
3476 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3477 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3478 /* we found the server and it's usable */
3479 t->flags &= ~SN_CK_MASK;
3480 t->flags |= SN_CK_VALID | SN_DIRECT;
3481 t->srv = srv;
3482 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003483 } else {
willy tarreau12350152005-12-18 01:03:27 +01003484 t->flags &= ~SN_CK_MASK;
3485 t->flags |= SN_CK_DOWN;
3486 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003487 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003488 srv = srv->next;
3489 }/* end while(srv) */
3490 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003491 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003492 else {
3493 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3494 }
willy tarreau598da412005-12-18 01:07:29 +01003495 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003496 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003497 else{
3498 //printf("No Methode-Header with Session-String\n");
3499 }
3500
willy tarreau8337c6b2005-12-17 13:41:01 +01003501 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003502 /* we have a complete HTTP request that we must log */
3503 int urilen;
3504
willy tarreaua1598082005-12-17 13:08:06 +01003505 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003506 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003507 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003508 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003509 if (!(t->flags & SN_ERR_MASK))
3510 t->flags |= SN_ERR_PRXCOND;
3511 if (!(t->flags & SN_FINST_MASK))
3512 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003513 return 1;
3514 }
3515
3516 urilen = ptr - req->h;
3517 if (urilen >= REQURI_LEN)
3518 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003519 memcpy(t->logs.uri, req->h, urilen);
3520 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003521
willy tarreaua1598082005-12-17 13:08:06 +01003522 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003523 sess_log(t);
3524 }
willy tarreau4302f492005-12-18 01:00:37 +01003525 else if (t->logs.logwait & LW_REQHDR) {
3526 struct cap_hdr *h;
3527 int len;
3528 for (h = t->proxy->req_cap; h; h = h->next) {
3529 if ((h->namelen + 2 <= ptr - req->h) &&
3530 (req->h[h->namelen] == ':') &&
3531 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3532
3533 if (t->req_cap[h->index] == NULL)
3534 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3535
3536 len = ptr - (req->h + h->namelen + 2);
3537 if (len > h->len)
3538 len = h->len;
3539
3540 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3541 t->req_cap[h->index][len]=0;
3542 }
3543 }
3544
3545 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003546
willy tarreau5cbea6f2005-12-17 12:48:26 +01003547 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003548
willy tarreau982249e2005-12-18 00:57:06 +01003549 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003550 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003551 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 +01003552 max = ptr - req->h;
3553 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003554 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003555 trash[len++] = '\n';
3556 write(1, trash, len);
3557 }
willy tarreau0f7af912005-12-17 12:21:26 +01003558
willy tarreau25c4ea52005-12-18 00:49:49 +01003559
3560 /* remove "connection: " if needed */
3561 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3562 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3563 delete_header = 1;
3564 }
3565
willy tarreau5cbea6f2005-12-17 12:48:26 +01003566 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003567 if (!delete_header && t->proxy->req_exp != NULL
3568 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003569 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003570 char term;
3571
3572 term = *ptr;
3573 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003574 exp = t->proxy->req_exp;
3575 do {
3576 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3577 switch (exp->action) {
3578 case ACT_ALLOW:
3579 if (!(t->flags & SN_CLDENY))
3580 t->flags |= SN_CLALLOW;
3581 break;
3582 case ACT_REPLACE:
3583 if (!(t->flags & SN_CLDENY)) {
3584 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3585 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3586 }
3587 break;
3588 case ACT_REMOVE:
3589 if (!(t->flags & SN_CLDENY))
3590 delete_header = 1;
3591 break;
3592 case ACT_DENY:
3593 if (!(t->flags & SN_CLALLOW))
3594 t->flags |= SN_CLDENY;
3595 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003596 case ACT_PASS: /* we simply don't deny this one */
3597 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003598 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003599 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003600 }
willy tarreaue39cd132005-12-17 13:00:18 +01003601 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003602 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003603 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003604
willy tarreau240afa62005-12-17 13:14:35 +01003605 /* Now look for cookies. Conforming to RFC2109, we have to support
3606 * attributes whose name begin with a '$', and associate them with
3607 * the right cookie, if we want to delete this cookie.
3608 * So there are 3 cases for each cookie read :
3609 * 1) it's a special attribute, beginning with a '$' : ignore it.
3610 * 2) it's a server id cookie that we *MAY* want to delete : save
3611 * some pointers on it (last semi-colon, beginning of cookie...)
3612 * 3) it's an application cookie : we *MAY* have to delete a previous
3613 * "special" cookie.
3614 * At the end of loop, if a "special" cookie remains, we may have to
3615 * remove it. If no application cookie persists in the header, we
3616 * *MUST* delete it
3617 */
willy tarreau12350152005-12-18 01:03:27 +01003618 if (!delete_header &&
3619 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003620 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003621 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003622 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003623 char *del_colon, *del_cookie, *colon;
3624 int app_cookies;
3625
willy tarreau5cbea6f2005-12-17 12:48:26 +01003626 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003627 colon = p1;
3628 /* del_cookie == NULL => nothing to be deleted */
3629 del_colon = del_cookie = NULL;
3630 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003631
3632 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003633 /* skip spaces and colons, but keep an eye on these ones */
3634 while (p1 < ptr) {
3635 if (*p1 == ';' || *p1 == ',')
3636 colon = p1;
3637 else if (!isspace((int)*p1))
3638 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003639 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003640 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003641
3642 if (p1 == ptr)
3643 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003644
3645 /* p1 is at the beginning of the cookie name */
3646 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003647 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003648 p2++;
3649
3650 if (p2 == ptr)
3651 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003652
3653 p3 = p2 + 1; /* skips the '=' sign */
3654 if (p3 == ptr)
3655 break;
3656
willy tarreau240afa62005-12-17 13:14:35 +01003657 p4 = p3;
3658 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003659 p4++;
3660
3661 /* here, we have the cookie name between p1 and p2,
3662 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003663 * we can process it :
3664 *
3665 * Cookie: NAME=VALUE;
3666 * | || || |
3667 * | || || +--> p4
3668 * | || |+-------> p3
3669 * | || +--------> p2
3670 * | |+------------> p1
3671 * | +-------------> colon
3672 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003673 */
3674
willy tarreau240afa62005-12-17 13:14:35 +01003675 if (*p1 == '$') {
3676 /* skip this one */
3677 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003678 else {
3679 /* first, let's see if we want to capture it */
3680 if (t->proxy->capture_name != NULL &&
3681 t->logs.cli_cookie == NULL &&
3682 (p4 - p1 >= t->proxy->capture_namelen) &&
3683 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3684 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003685
willy tarreau8337c6b2005-12-17 13:41:01 +01003686 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3687 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003688 } else {
3689 if (log_len > t->proxy->capture_len)
3690 log_len = t->proxy->capture_len;
3691 memcpy(t->logs.cli_cookie, p1, log_len);
3692 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003693 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003694 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003695
3696 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3697 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3698 /* Cool... it's the right one */
3699 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003700 char *delim;
3701
3702 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3703 * have the server ID betweek p3 and delim, and the original cookie between
3704 * delim+1 and p4. Otherwise, delim==p4 :
3705 *
3706 * Cookie: NAME=SRV~VALUE;
3707 * | || || | |
3708 * | || || | +--> p4
3709 * | || || +--------> delim
3710 * | || |+-----------> p3
3711 * | || +------------> p2
3712 * | |+----------------> p1
3713 * | +-----------------> colon
3714 * +------------------------> req->h
3715 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003716
willy tarreau0174f312005-12-18 01:02:42 +01003717 if (t->proxy->options & PR_O_COOK_PFX) {
3718 for (delim = p3; delim < p4; delim++)
3719 if (*delim == COOKIE_DELIM)
3720 break;
3721 }
3722 else
3723 delim = p4;
3724
3725
3726 /* Here, we'll look for the first running server which supports the cookie.
3727 * This allows to share a same cookie between several servers, for example
3728 * to dedicate backup servers to specific servers only.
3729 */
3730 while (srv) {
3731 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3732 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3733 /* we found the server and it's usable */
3734 t->flags &= ~SN_CK_MASK;
3735 t->flags |= SN_CK_VALID | SN_DIRECT;
3736 t->srv = srv;
3737 break;
willy tarreau12350152005-12-18 01:03:27 +01003738 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003739 /* we found a server, but it's down */
3740 t->flags &= ~SN_CK_MASK;
3741 t->flags |= SN_CK_DOWN;
3742 }
3743 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003744 srv = srv->next;
3745 }
3746
willy tarreau0174f312005-12-18 01:02:42 +01003747 if (!srv && !(t->flags & SN_CK_DOWN)) {
3748 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003749 t->flags &= ~SN_CK_MASK;
3750 t->flags |= SN_CK_INVALID;
3751 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003752
willy tarreau0174f312005-12-18 01:02:42 +01003753 /* depending on the cookie mode, we may have to either :
3754 * - delete the complete cookie if we're in insert+indirect mode, so that
3755 * the server never sees it ;
3756 * - remove the server id from the cookie value, and tag the cookie as an
3757 * application cookie so that it does not get accidentely removed later,
3758 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003759 */
willy tarreau0174f312005-12-18 01:02:42 +01003760 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3761 buffer_replace2(req, p3, delim + 1, NULL, 0);
3762 p4 -= (delim + 1 - p3);
3763 ptr -= (delim + 1 - p3);
3764 del_cookie = del_colon = NULL;
3765 app_cookies++; /* protect the header from deletion */
3766 }
3767 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003768 (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 +01003769 del_cookie = p1;
3770 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003771 }
willy tarreau12350152005-12-18 01:03:27 +01003772 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003773 /* now we know that we must keep this cookie since it's
3774 * not ours. But if we wanted to delete our cookie
3775 * earlier, we cannot remove the complete header, but we
3776 * can remove the previous block itself.
3777 */
3778 app_cookies++;
3779
3780 if (del_cookie != NULL) {
3781 buffer_replace2(req, del_cookie, p1, NULL, 0);
3782 p4 -= (p1 - del_cookie);
3783 ptr -= (p1 - del_cookie);
3784 del_cookie = del_colon = NULL;
3785 }
willy tarreau240afa62005-12-17 13:14:35 +01003786 }
willy tarreau12350152005-12-18 01:03:27 +01003787
3788 if ((t->proxy->appsession_name != NULL) &&
3789 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3790 /* first, let's see if the cookie is our appcookie*/
3791
3792 /* Cool... it's the right one */
3793
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->sessid:malloc().\n");
3798 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3799 return 0;
3800 }
3801
3802 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3803 asession_temp->sessid[t->proxy->appsession_len] = 0;
3804 asession_temp->serverid = NULL;
3805
3806 /* only do insert, if lookup fails */
3807 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3808 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3809 Alert("Not enough memory process_cli():asession:calloc().\n");
3810 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3811 return 0;
3812 }
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);
3817 }
3818 else{
3819 /* free wasted memory */
3820 pool_free_to(apools.sessid, local_asession.sessid);
3821 }
3822
3823 if (asession_temp->serverid == NULL) {
3824 Alert("Found Application Session without matching server.\n");
3825 } else {
3826 struct server *srv = t->proxy->srv;
3827 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003828 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003829 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3830 /* we found the server and it's usable */
3831 t->flags &= ~SN_CK_MASK;
3832 t->flags |= SN_CK_VALID | SN_DIRECT;
3833 t->srv = srv;
3834 break;
3835 } else {
3836 t->flags &= ~SN_CK_MASK;
3837 t->flags |= SN_CK_DOWN;
3838 }
3839 }
3840 srv = srv->next;
3841 }/* end while(srv) */
3842 }/* end else if server == NULL */
3843
3844 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003845 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003846 }
willy tarreau240afa62005-12-17 13:14:35 +01003847
willy tarreau5cbea6f2005-12-17 12:48:26 +01003848 /* we'll have to look for another cookie ... */
3849 p1 = p4;
3850 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003851
3852 /* There's no more cookie on this line.
3853 * We may have marked the last one(s) for deletion.
3854 * We must do this now in two ways :
3855 * - if there is no app cookie, we simply delete the header ;
3856 * - if there are app cookies, we must delete the end of the
3857 * string properly, including the colon/semi-colon before
3858 * the cookie name.
3859 */
3860 if (del_cookie != NULL) {
3861 if (app_cookies) {
3862 buffer_replace2(req, del_colon, ptr, NULL, 0);
3863 /* WARNING! <ptr> becomes invalid for now. If some code
3864 * below needs to rely on it before the end of the global
3865 * header loop, we need to correct it with this code :
3866 * ptr = del_colon;
3867 */
3868 }
3869 else
3870 delete_header = 1;
3871 }
3872 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003873
3874 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003875 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003876 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003877 }
willy tarreau240afa62005-12-17 13:14:35 +01003878 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3879
willy tarreau5cbea6f2005-12-17 12:48:26 +01003880 req->h = req->lr;
3881 } /* while (req->lr < req->r) */
3882
3883 /* end of header processing (even if incomplete) */
3884
willy tarreauef900ab2005-12-17 12:52:52 +01003885 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3886 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3887 * full. We cannot loop here since event_cli_read will disable it only if
3888 * req->l == rlim-data
3889 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003890 FD_SET(t->cli_fd, StaticReadEvent);
3891 if (t->proxy->clitimeout)
3892 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3893 else
3894 tv_eternity(&t->crexpire);
3895 }
3896
willy tarreaue39cd132005-12-17 13:00:18 +01003897 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003898 * won't be able to free more later, so the session will never terminate.
3899 */
willy tarreaue39cd132005-12-17 13:00:18 +01003900 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003901 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003902 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003903 if (!(t->flags & SN_ERR_MASK))
3904 t->flags |= SN_ERR_PRXCOND;
3905 if (!(t->flags & SN_FINST_MASK))
3906 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003907 return 1;
3908 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003909 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003910 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003911 tv_eternity(&t->crexpire);
3912 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003913 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003914 if (!(t->flags & SN_ERR_MASK))
3915 t->flags |= SN_ERR_CLICL;
3916 if (!(t->flags & SN_FINST_MASK))
3917 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003918 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003919 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003920 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3921
3922 /* read timeout : give up with an error message.
3923 */
3924 t->logs.status = 408;
3925 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003926 if (!(t->flags & SN_ERR_MASK))
3927 t->flags |= SN_ERR_CLITO;
3928 if (!(t->flags & SN_FINST_MASK))
3929 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003930 return 1;
3931 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003932
3933 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003934 }
3935 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003936 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003937 /* FIXME: this error handling is partly buggy because we always report
3938 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3939 * or HEADER phase. BTW, it's not logical to expire the client while
3940 * we're waiting for the server to connect.
3941 */
willy tarreau0f7af912005-12-17 12:21:26 +01003942 /* read or write error */
3943 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003944 tv_eternity(&t->crexpire);
3945 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003946 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003947 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003948 if (!(t->flags & SN_ERR_MASK))
3949 t->flags |= SN_ERR_CLICL;
3950 if (!(t->flags & SN_FINST_MASK))
3951 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003952 return 1;
3953 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003954 /* last read, or end of server write */
3955 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003956 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003957 tv_eternity(&t->crexpire);
3958 shutdown(t->cli_fd, SHUT_RD);
3959 t->cli_state = CL_STSHUTR;
3960 return 1;
3961 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003962 /* last server read and buffer empty */
3963 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003964 FD_CLR(t->cli_fd, StaticWriteEvent);
3965 tv_eternity(&t->cwexpire);
3966 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003967 /* We must ensure that the read part is still alive when switching
3968 * to shutw */
3969 FD_SET(t->cli_fd, StaticReadEvent);
3970 if (t->proxy->clitimeout)
3971 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003972 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003973 //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 +01003974 return 1;
3975 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003976 /* read timeout */
3977 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3978 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003979 tv_eternity(&t->crexpire);
3980 shutdown(t->cli_fd, SHUT_RD);
3981 t->cli_state = CL_STSHUTR;
3982 if (!(t->flags & SN_ERR_MASK))
3983 t->flags |= SN_ERR_CLITO;
3984 if (!(t->flags & SN_FINST_MASK))
3985 t->flags |= SN_FINST_D;
3986 return 1;
3987 }
3988 /* write timeout */
3989 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3990 FD_CLR(t->cli_fd, StaticWriteEvent);
3991 tv_eternity(&t->cwexpire);
3992 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003993 /* We must ensure that the read part is still alive when switching
3994 * to shutw */
3995 FD_SET(t->cli_fd, StaticReadEvent);
3996 if (t->proxy->clitimeout)
3997 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3998
willy tarreau036e1ce2005-12-17 13:46:33 +01003999 t->cli_state = CL_STSHUTW;
4000 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004001 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01004002 if (!(t->flags & SN_FINST_MASK))
4003 t->flags |= SN_FINST_D;
4004 return 1;
4005 }
willy tarreau0f7af912005-12-17 12:21:26 +01004006
willy tarreauc58fc692005-12-17 14:13:08 +01004007 if (req->l >= req->rlim - req->data) {
4008 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004009 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004010 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004011 FD_CLR(t->cli_fd, StaticReadEvent);
4012 tv_eternity(&t->crexpire);
4013 }
4014 }
4015 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004016 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004017 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4018 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004019 if (!t->proxy->clitimeout ||
4020 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4021 /* If the client has no timeout, or if the server not ready yet, and we
4022 * know for sure that it can expire, then it's cleaner to disable the
4023 * timeout on the client side so that too low values cannot make the
4024 * sessions abort too early.
4025 */
willy tarreau0f7af912005-12-17 12:21:26 +01004026 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004027 else
4028 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004029 }
4030 }
4031
4032 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004033 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004034 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4035 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4036 tv_eternity(&t->cwexpire);
4037 }
4038 }
4039 else { /* buffer not empty */
4040 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4041 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004042 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004043 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004044 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4045 t->crexpire = t->cwexpire;
4046 }
willy tarreau0f7af912005-12-17 12:21:26 +01004047 else
4048 tv_eternity(&t->cwexpire);
4049 }
4050 }
4051 return 0; /* other cases change nothing */
4052 }
4053 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004054 if (t->res_cw == RES_ERROR) {
4055 tv_eternity(&t->cwexpire);
4056 fd_delete(t->cli_fd);
4057 t->cli_state = CL_STCLOSE;
4058 if (!(t->flags & SN_ERR_MASK))
4059 t->flags |= SN_ERR_CLICL;
4060 if (!(t->flags & SN_FINST_MASK))
4061 t->flags |= SN_FINST_D;
4062 return 1;
4063 }
4064 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004065 tv_eternity(&t->cwexpire);
4066 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004067 t->cli_state = CL_STCLOSE;
4068 return 1;
4069 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004070 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4071 tv_eternity(&t->cwexpire);
4072 fd_delete(t->cli_fd);
4073 t->cli_state = CL_STCLOSE;
4074 if (!(t->flags & SN_ERR_MASK))
4075 t->flags |= SN_ERR_CLITO;
4076 if (!(t->flags & SN_FINST_MASK))
4077 t->flags |= SN_FINST_D;
4078 return 1;
4079 }
willy tarreau0f7af912005-12-17 12:21:26 +01004080 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004081 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004082 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4083 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4084 tv_eternity(&t->cwexpire);
4085 }
4086 }
4087 else { /* buffer not empty */
4088 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4089 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004090 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004091 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004092 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4093 t->crexpire = t->cwexpire;
4094 }
willy tarreau0f7af912005-12-17 12:21:26 +01004095 else
4096 tv_eternity(&t->cwexpire);
4097 }
4098 }
4099 return 0;
4100 }
4101 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004102 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004103 tv_eternity(&t->crexpire);
4104 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004105 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004106 if (!(t->flags & SN_ERR_MASK))
4107 t->flags |= SN_ERR_CLICL;
4108 if (!(t->flags & SN_FINST_MASK))
4109 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004110 return 1;
4111 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004112 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4113 tv_eternity(&t->crexpire);
4114 fd_delete(t->cli_fd);
4115 t->cli_state = CL_STCLOSE;
4116 return 1;
4117 }
4118 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4119 tv_eternity(&t->crexpire);
4120 fd_delete(t->cli_fd);
4121 t->cli_state = CL_STCLOSE;
4122 if (!(t->flags & SN_ERR_MASK))
4123 t->flags |= SN_ERR_CLITO;
4124 if (!(t->flags & SN_FINST_MASK))
4125 t->flags |= SN_FINST_D;
4126 return 1;
4127 }
willy tarreauef900ab2005-12-17 12:52:52 +01004128 else if (req->l >= req->rlim - req->data) {
4129 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004130
4131 /* FIXME-20050705: is it possible for a client to maintain a session
4132 * after the timeout by sending more data after it receives a close ?
4133 */
4134
willy tarreau0f7af912005-12-17 12:21:26 +01004135 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004136 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004137 FD_CLR(t->cli_fd, StaticReadEvent);
4138 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004139 //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 +01004140 }
4141 }
4142 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004143 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004144 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4145 FD_SET(t->cli_fd, StaticReadEvent);
4146 if (t->proxy->clitimeout)
4147 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4148 else
4149 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004150 //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 +01004151 }
4152 }
4153 return 0;
4154 }
4155 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004156 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004157 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004158 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 +01004159 write(1, trash, len);
4160 }
4161 return 0;
4162 }
4163 return 0;
4164}
4165
4166
4167/*
4168 * manages the server FSM and its socket. It returns 1 if a state has changed
4169 * (and a resync may be needed), 0 else.
4170 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004171int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004172 int s = t->srv_state;
4173 int c = t->cli_state;
4174 struct buffer *req = t->req;
4175 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004176 appsess *asession_temp = NULL;
4177 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004178 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004179
willy tarreau750a4722005-12-17 13:21:24 +01004180#ifdef DEBUG_FULL
4181 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4182#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004183 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4184 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4185 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4186 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004187 if (s == SV_STIDLE) {
4188 if (c == CL_STHEADERS)
4189 return 0; /* stay in idle, waiting for data to reach the client side */
4190 else if (c == CL_STCLOSE ||
4191 c == CL_STSHUTW ||
4192 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4193 tv_eternity(&t->cnexpire);
4194 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004195 if (!(t->flags & SN_ERR_MASK))
4196 t->flags |= SN_ERR_CLICL;
4197 if (!(t->flags & SN_FINST_MASK))
4198 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004199 return 1;
4200 }
4201 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01004202 /* initiate a connection to the server */
4203 conn_err = connect_server(t);
4204 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004205 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4206 t->srv_state = SV_STCONN;
4207 }
4208 else { /* try again */
4209 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004210 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004211 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004212 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004213 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4214 t->flags &= ~SN_CK_MASK;
4215 t->flags |= SN_CK_DOWN;
4216 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004217 }
4218
willy tarreaub1285d52005-12-18 01:20:14 +01004219 conn_err = connect_server(t);
4220 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004221 t->srv_state = SV_STCONN;
4222 break;
4223 }
4224 }
4225 if (t->conn_retries < 0) {
4226 /* if conn_retries < 0 or other error, let's abort */
4227 tv_eternity(&t->cnexpire);
4228 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004229 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004230 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004231 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004232 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004233 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004234 if (!(t->flags & SN_FINST_MASK))
4235 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004236 }
4237 }
4238 return 1;
4239 }
4240 }
4241 else if (s == SV_STCONN) { /* connection in progress */
4242 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004243 //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 +01004244 return 0; /* nothing changed */
4245 }
4246 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4247 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4248 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004249 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004250 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004251 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004252 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004253 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004254 if (t->conn_retries >= 0) {
4255 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004256 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004257 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004258 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4259 t->flags &= ~SN_CK_MASK;
4260 t->flags |= SN_CK_DOWN;
4261 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004262 }
willy tarreaub1285d52005-12-18 01:20:14 +01004263 conn_err = connect_server(t);
4264 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004265 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004266 }
willy tarreaub1285d52005-12-18 01:20:14 +01004267 else if (t->res_sw == RES_SILENT)
4268 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4269 else
4270 conn_err = SN_ERR_SRVCL; // it was a connect error.
4271
willy tarreau0f7af912005-12-17 12:21:26 +01004272 /* if conn_retries < 0 or other error, let's abort */
4273 tv_eternity(&t->cnexpire);
4274 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004275 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004276 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004277 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004278 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004279 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004280 if (!(t->flags & SN_FINST_MASK))
4281 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004282 return 1;
4283 }
4284 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004285 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004286
willy tarreau0f7af912005-12-17 12:21:26 +01004287 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004288 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004289 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004290 tv_eternity(&t->swexpire);
4291 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004292 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004293 if (t->proxy->srvtimeout) {
4294 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4295 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4296 t->srexpire = t->swexpire;
4297 }
4298 else
4299 tv_eternity(&t->swexpire);
4300 }
willy tarreau0f7af912005-12-17 12:21:26 +01004301
4302 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4303 FD_SET(t->srv_fd, StaticReadEvent);
4304 if (t->proxy->srvtimeout)
4305 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4306 else
4307 tv_eternity(&t->srexpire);
4308
4309 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004310 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004311
4312 /* if the user wants to log as soon as possible, without counting
4313 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004314 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004315 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4316 sess_log(t);
4317 }
willy tarreau0f7af912005-12-17 12:21:26 +01004318 }
willy tarreauef900ab2005-12-17 12:52:52 +01004319 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004320 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004321 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4322 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004323 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004324 return 1;
4325 }
4326 }
4327 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004328 /* now parse the partial (or complete) headers */
4329 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4330 char *ptr;
4331 int delete_header;
4332
4333 ptr = rep->lr;
4334
4335 /* look for the end of the current header */
4336 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4337 ptr++;
4338
4339 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004340 int line, len;
4341
4342 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004343
4344 /* first, we'll block if security checks have caught nasty things */
4345 if (t->flags & SN_CACHEABLE) {
4346 if ((t->flags & SN_CACHE_COOK) &&
4347 (t->flags & SN_SCK_ANY) &&
4348 (t->proxy->options & PR_O_CHK_CACHE)) {
4349
4350 /* we're in presence of a cacheable response containing
4351 * a set-cookie header. We'll block it as requested by
4352 * the 'checkcache' option, and send an alert.
4353 */
4354 tv_eternity(&t->srexpire);
4355 tv_eternity(&t->swexpire);
4356 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004357 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01004358 t->srv_state = SV_STCLOSE;
4359 t->logs.status = 502;
4360 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4361 if (!(t->flags & SN_ERR_MASK))
4362 t->flags |= SN_ERR_PRXCOND;
4363 if (!(t->flags & SN_FINST_MASK))
4364 t->flags |= SN_FINST_H;
4365
4366 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4367 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4368
4369 return 1;
4370 }
4371 }
4372
willy tarreau982249e2005-12-18 00:57:06 +01004373 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4374 if (t->flags & SN_SVDENY) {
4375 tv_eternity(&t->srexpire);
4376 tv_eternity(&t->swexpire);
4377 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004378 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01004379 t->srv_state = SV_STCLOSE;
4380 t->logs.status = 502;
4381 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4382 if (!(t->flags & SN_ERR_MASK))
4383 t->flags |= SN_ERR_PRXCOND;
4384 if (!(t->flags & SN_FINST_MASK))
4385 t->flags |= SN_FINST_H;
4386 return 1;
4387 }
4388
willy tarreau5cbea6f2005-12-17 12:48:26 +01004389 /* we'll have something else to do here : add new headers ... */
4390
willy tarreaucd878942005-12-17 13:27:43 +01004391 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4392 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004393 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004394 * insert a set-cookie here, except if we want to insert only on POST
4395 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004396 */
willy tarreau750a4722005-12-17 13:21:24 +01004397 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004398 t->proxy->cookie_name,
4399 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004400
willy tarreau036e1ce2005-12-17 13:46:33 +01004401 t->flags |= SN_SCK_INSERTED;
4402
willy tarreau750a4722005-12-17 13:21:24 +01004403 /* Here, we will tell an eventual cache on the client side that we don't
4404 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4405 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4406 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4407 */
willy tarreau240afa62005-12-17 13:14:35 +01004408 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004409 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4410 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004411
4412 if (rep->data + rep->l < rep->h)
4413 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4414 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004415 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004416 }
4417
4418 /* headers to be added */
4419 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004420 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4421 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004422 }
4423
willy tarreau25c4ea52005-12-18 00:49:49 +01004424 /* add a "connection: close" line if needed */
4425 if (t->proxy->options & PR_O_HTTP_CLOSE)
4426 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4427
willy tarreau5cbea6f2005-12-17 12:48:26 +01004428 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004429 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004430 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004431
Willy TARREAU767ba712006-03-01 22:40:50 +01004432 /* client connection already closed or option 'httpclose' required :
4433 * we close the server's outgoing connection right now.
4434 */
4435 if ((req->l == 0) &&
4436 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4437 FD_CLR(t->srv_fd, StaticWriteEvent);
4438 tv_eternity(&t->swexpire);
4439
4440 /* We must ensure that the read part is still alive when switching
4441 * to shutw */
4442 FD_SET(t->srv_fd, StaticReadEvent);
4443 if (t->proxy->srvtimeout)
4444 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4445
4446 shutdown(t->srv_fd, SHUT_WR);
4447 t->srv_state = SV_STSHUTW;
4448 }
4449
willy tarreau25c4ea52005-12-18 00:49:49 +01004450 /* if the user wants to log as soon as possible, without counting
4451 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004452 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004453 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4454 t->logs.bytes = rep->h - rep->data;
4455 sess_log(t);
4456 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004457 break;
4458 }
4459
4460 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4461 if (ptr > rep->r - 2) {
4462 /* this is a partial header, let's wait for more to come */
4463 rep->lr = ptr;
4464 break;
4465 }
4466
4467 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4468 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4469
4470 /* now we know that *ptr is either \r or \n,
4471 * and that there are at least 1 char after it.
4472 */
4473 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4474 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4475 else
4476 rep->lr = ptr + 2; /* \r\n or \n\r */
4477
4478 /*
4479 * now we know that we have a full header ; we can do whatever
4480 * we want with these pointers :
4481 * rep->h = beginning of header
4482 * ptr = end of header (first \r or \n)
4483 * rep->lr = beginning of next line (next rep->h)
4484 * rep->r = end of data (not used at this stage)
4485 */
4486
willy tarreaua1598082005-12-17 13:08:06 +01004487
willy tarreau982249e2005-12-18 00:57:06 +01004488 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004489 t->logs.logwait &= ~LW_RESP;
4490 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004491 switch (t->logs.status) {
4492 case 200:
4493 case 203:
4494 case 206:
4495 case 300:
4496 case 301:
4497 case 410:
4498 /* RFC2616 @13.4:
4499 * "A response received with a status code of
4500 * 200, 203, 206, 300, 301 or 410 MAY be stored
4501 * by a cache (...) unless a cache-control
4502 * directive prohibits caching."
4503 *
4504 * RFC2616 @9.5: POST method :
4505 * "Responses to this method are not cacheable,
4506 * unless the response includes appropriate
4507 * Cache-Control or Expires header fields."
4508 */
4509 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4510 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4511 break;
4512 default:
4513 break;
4514 }
willy tarreau4302f492005-12-18 01:00:37 +01004515 }
4516 else if (t->logs.logwait & LW_RSPHDR) {
4517 struct cap_hdr *h;
4518 int len;
4519 for (h = t->proxy->rsp_cap; h; h = h->next) {
4520 if ((h->namelen + 2 <= ptr - rep->h) &&
4521 (rep->h[h->namelen] == ':') &&
4522 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4523
4524 if (t->rsp_cap[h->index] == NULL)
4525 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4526
4527 len = ptr - (rep->h + h->namelen + 2);
4528 if (len > h->len)
4529 len = h->len;
4530
4531 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4532 t->rsp_cap[h->index][len]=0;
4533 }
4534 }
4535
willy tarreaua1598082005-12-17 13:08:06 +01004536 }
4537
willy tarreau5cbea6f2005-12-17 12:48:26 +01004538 delete_header = 0;
4539
willy tarreau982249e2005-12-18 00:57:06 +01004540 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004541 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004542 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 +01004543 max = ptr - rep->h;
4544 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004545 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004546 trash[len++] = '\n';
4547 write(1, trash, len);
4548 }
4549
willy tarreau25c4ea52005-12-18 00:49:49 +01004550 /* remove "connection: " if needed */
4551 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4552 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4553 delete_header = 1;
4554 }
4555
willy tarreau5cbea6f2005-12-17 12:48:26 +01004556 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004557 if (!delete_header && t->proxy->rsp_exp != NULL
4558 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004559 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004560 char term;
4561
4562 term = *ptr;
4563 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004564 exp = t->proxy->rsp_exp;
4565 do {
4566 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4567 switch (exp->action) {
4568 case ACT_ALLOW:
4569 if (!(t->flags & SN_SVDENY))
4570 t->flags |= SN_SVALLOW;
4571 break;
4572 case ACT_REPLACE:
4573 if (!(t->flags & SN_SVDENY)) {
4574 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4575 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4576 }
4577 break;
4578 case ACT_REMOVE:
4579 if (!(t->flags & SN_SVDENY))
4580 delete_header = 1;
4581 break;
4582 case ACT_DENY:
4583 if (!(t->flags & SN_SVALLOW))
4584 t->flags |= SN_SVDENY;
4585 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004586 case ACT_PASS: /* we simply don't deny this one */
4587 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004588 }
4589 break;
4590 }
willy tarreaue39cd132005-12-17 13:00:18 +01004591 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004592 *ptr = term; /* restore the string terminator */
4593 }
4594
willy tarreau97f58572005-12-18 00:53:44 +01004595 /* check for cache-control: or pragma: headers */
4596 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4597 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4598 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4599 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4600 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004601 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004602 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4603 else {
4604 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004605 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004606 t->flags &= ~SN_CACHE_COOK;
4607 }
4608 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004609 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004610 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004611 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004612 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4613 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004614 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004615 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004616 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4617 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4618 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4619 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4620 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4621 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004622 }
4623 }
4624 }
4625
willy tarreau5cbea6f2005-12-17 12:48:26 +01004626 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004627 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004628 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004629 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004630 char *p1, *p2, *p3, *p4;
4631
willy tarreau97f58572005-12-18 00:53:44 +01004632 t->flags |= SN_SCK_ANY;
4633
willy tarreau5cbea6f2005-12-17 12:48:26 +01004634 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4635
4636 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004637 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004638 p1++;
4639
4640 if (p1 == ptr || *p1 == ';') /* end of cookie */
4641 break;
4642
4643 /* p1 is at the beginning of the cookie name */
4644 p2 = p1;
4645
4646 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4647 p2++;
4648
4649 if (p2 == ptr || *p2 == ';') /* next cookie */
4650 break;
4651
4652 p3 = p2 + 1; /* skips the '=' sign */
4653 if (p3 == ptr)
4654 break;
4655
4656 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004657 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004658 p4++;
4659
4660 /* here, we have the cookie name between p1 and p2,
4661 * and its value between p3 and p4.
4662 * we can process it.
4663 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004664
4665 /* first, let's see if we want to capture it */
4666 if (t->proxy->capture_name != NULL &&
4667 t->logs.srv_cookie == NULL &&
4668 (p4 - p1 >= t->proxy->capture_namelen) &&
4669 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4670 int log_len = p4 - p1;
4671
4672 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4673 Alert("HTTP logging : out of memory.\n");
4674 }
4675
4676 if (log_len > t->proxy->capture_len)
4677 log_len = t->proxy->capture_len;
4678 memcpy(t->logs.srv_cookie, p1, log_len);
4679 t->logs.srv_cookie[log_len] = 0;
4680 }
4681
4682 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4683 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004684 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004685 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004686
4687 /* If the cookie is in insert mode on a known server, we'll delete
4688 * this occurrence because we'll insert another one later.
4689 * We'll delete it too if the "indirect" option is set and we're in
4690 * a direct access. */
4691 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004692 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004693 /* this header must be deleted */
4694 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004695 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004696 }
4697 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4698 /* replace bytes p3->p4 with the cookie name associated
4699 * with this server since we know it.
4700 */
4701 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004702 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004703 }
willy tarreau0174f312005-12-18 01:02:42 +01004704 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4705 /* insert the cookie name associated with this server
4706 * before existing cookie, and insert a delimitor between them..
4707 */
4708 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4709 p3[t->srv->cklen] = COOKIE_DELIM;
4710 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4711 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004712 break;
4713 }
willy tarreau12350152005-12-18 01:03:27 +01004714
4715 /* first, let's see if the cookie is our appcookie*/
4716 if ((t->proxy->appsession_name != NULL) &&
4717 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4718
4719 /* Cool... it's the right one */
4720
willy tarreaub952e1d2005-12-18 01:31:20 +01004721 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004722 asession_temp = &local_asession;
4723
willy tarreaub952e1d2005-12-18 01:31:20 +01004724 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004725 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4726 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4727 }
4728 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4729 asession_temp->sessid[t->proxy->appsession_len] = 0;
4730 asession_temp->serverid = NULL;
4731
4732 /* only do insert, if lookup fails */
4733 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4734 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4735 Alert("Not enought Memory process_srv():asession:calloc().\n");
4736 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4737 return 0;
4738 }
4739 asession_temp->sessid = local_asession.sessid;
4740 asession_temp->serverid = local_asession.serverid;
4741 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004742 }/* end if (chtbl_lookup()) */
4743 else {
willy tarreau12350152005-12-18 01:03:27 +01004744 /* free wasted memory */
4745 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004746 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004747
willy tarreaub952e1d2005-12-18 01:31:20 +01004748 if (asession_temp->serverid == NULL) {
4749 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004750 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4751 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4752 }
4753 asession_temp->serverid[0] = '\0';
4754 }
4755
willy tarreaub952e1d2005-12-18 01:31:20 +01004756 if (asession_temp->serverid[0] == '\0')
4757 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004758
4759 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4760
4761#if defined(DEBUG_HASH)
4762 print_table(&(t->proxy->htbl_proxy));
4763#endif
4764 break;
4765 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004766 else {
4767 // fprintf(stderr,"Ignoring unknown cookie : ");
4768 // write(2, p1, p2-p1);
4769 // fprintf(stderr," = ");
4770 // write(2, p3, p4-p3);
4771 // fprintf(stderr,"\n");
4772 }
4773 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4774 } /* we're now at the end of the cookie value */
4775 } /* end of cookie processing */
4776
willy tarreau97f58572005-12-18 00:53:44 +01004777 /* check for any set-cookie in case we check for cacheability */
4778 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4779 (t->proxy->options & PR_O_CHK_CACHE) &&
4780 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4781 t->flags |= SN_SCK_ANY;
4782 }
4783
willy tarreau5cbea6f2005-12-17 12:48:26 +01004784 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004785 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004786 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004787
willy tarreau5cbea6f2005-12-17 12:48:26 +01004788 rep->h = rep->lr;
4789 } /* while (rep->lr < rep->r) */
4790
4791 /* end of header processing (even if incomplete) */
4792
willy tarreauef900ab2005-12-17 12:52:52 +01004793 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4794 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4795 * full. We cannot loop here since event_srv_read will disable it only if
4796 * rep->l == rlim-data
4797 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004798 FD_SET(t->srv_fd, StaticReadEvent);
4799 if (t->proxy->srvtimeout)
4800 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4801 else
4802 tv_eternity(&t->srexpire);
4803 }
willy tarreau0f7af912005-12-17 12:21:26 +01004804
willy tarreau8337c6b2005-12-17 13:41:01 +01004805 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004806 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004807 tv_eternity(&t->srexpire);
4808 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004809 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004810 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01004811 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004812 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004813 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004814 if (!(t->flags & SN_ERR_MASK))
4815 t->flags |= SN_ERR_SRVCL;
4816 if (!(t->flags & SN_FINST_MASK))
4817 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004818 return 1;
4819 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004820 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004821 * since we are in header mode, if there's no space left for headers, we
4822 * won't be able to free more later, so the session will never terminate.
4823 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004824 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 +01004825 FD_CLR(t->srv_fd, StaticReadEvent);
4826 tv_eternity(&t->srexpire);
4827 shutdown(t->srv_fd, SHUT_RD);
4828 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004829 //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 +01004830 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004831 }
4832 /* read timeout : return a 504 to the client.
4833 */
4834 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4835 tv_eternity(&t->srexpire);
4836 tv_eternity(&t->swexpire);
4837 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004838 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01004839 t->srv_state = SV_STCLOSE;
4840 t->logs.status = 504;
4841 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004842 if (!(t->flags & SN_ERR_MASK))
4843 t->flags |= SN_ERR_SRVTO;
4844 if (!(t->flags & SN_FINST_MASK))
4845 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004846 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004847
4848 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004849 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004850 /* FIXME!!! here, we don't want to switch to SHUTW if the
4851 * client shuts read too early, because we may still have
4852 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004853 * The side-effect is that if the client completely closes its
4854 * connection during SV_STHEADER, the connection to the server
4855 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004856 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004857 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004858 FD_CLR(t->srv_fd, StaticWriteEvent);
4859 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004860
4861 /* We must ensure that the read part is still alive when switching
4862 * to shutw */
4863 FD_SET(t->srv_fd, StaticReadEvent);
4864 if (t->proxy->srvtimeout)
4865 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4866
willy tarreau0f7af912005-12-17 12:21:26 +01004867 shutdown(t->srv_fd, SHUT_WR);
4868 t->srv_state = SV_STSHUTW;
4869 return 1;
4870 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004871 /* write timeout */
4872 /* FIXME!!! here, we don't want to switch to SHUTW if the
4873 * client shuts read too early, because we may still have
4874 * some work to do on the headers.
4875 */
4876 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4877 FD_CLR(t->srv_fd, StaticWriteEvent);
4878 tv_eternity(&t->swexpire);
4879 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004880 /* We must ensure that the read part is still alive when switching
4881 * to shutw */
4882 FD_SET(t->srv_fd, StaticReadEvent);
4883 if (t->proxy->srvtimeout)
4884 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4885
4886 /* We must ensure that the read part is still alive when switching
4887 * to shutw */
4888 FD_SET(t->srv_fd, StaticReadEvent);
4889 if (t->proxy->srvtimeout)
4890 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4891
willy tarreau036e1ce2005-12-17 13:46:33 +01004892 t->srv_state = SV_STSHUTW;
4893 if (!(t->flags & SN_ERR_MASK))
4894 t->flags |= SN_ERR_SRVTO;
4895 if (!(t->flags & SN_FINST_MASK))
4896 t->flags |= SN_FINST_H;
4897 return 1;
4898 }
willy tarreau0f7af912005-12-17 12:21:26 +01004899
4900 if (req->l == 0) {
4901 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4902 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4903 tv_eternity(&t->swexpire);
4904 }
4905 }
4906 else { /* client buffer not empty */
4907 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4908 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004909 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004910 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004911 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4912 t->srexpire = t->swexpire;
4913 }
willy tarreau0f7af912005-12-17 12:21:26 +01004914 else
4915 tv_eternity(&t->swexpire);
4916 }
4917 }
4918
willy tarreau5cbea6f2005-12-17 12:48:26 +01004919 /* be nice with the client side which would like to send a complete header
4920 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4921 * would read all remaining data at once ! The client should not write past rep->lr
4922 * when the server is in header state.
4923 */
4924 //return header_processed;
4925 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004926 }
4927 else if (s == SV_STDATA) {
4928 /* read or write error */
4929 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004930 tv_eternity(&t->srexpire);
4931 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004932 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004933 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01004934 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004935 if (!(t->flags & SN_ERR_MASK))
4936 t->flags |= SN_ERR_SRVCL;
4937 if (!(t->flags & SN_FINST_MASK))
4938 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004939 return 1;
4940 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004941 /* last read, or end of client write */
4942 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004943 FD_CLR(t->srv_fd, StaticReadEvent);
4944 tv_eternity(&t->srexpire);
4945 shutdown(t->srv_fd, SHUT_RD);
4946 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004947 //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 +01004948 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004949 }
4950 /* end of client read and no more data to send */
4951 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4952 FD_CLR(t->srv_fd, StaticWriteEvent);
4953 tv_eternity(&t->swexpire);
4954 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004955 /* We must ensure that the read part is still alive when switching
4956 * to shutw */
4957 FD_SET(t->srv_fd, StaticReadEvent);
4958 if (t->proxy->srvtimeout)
4959 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4960
willy tarreaua41a8b42005-12-17 14:02:24 +01004961 t->srv_state = SV_STSHUTW;
4962 return 1;
4963 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004964 /* read timeout */
4965 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4966 FD_CLR(t->srv_fd, StaticReadEvent);
4967 tv_eternity(&t->srexpire);
4968 shutdown(t->srv_fd, SHUT_RD);
4969 t->srv_state = SV_STSHUTR;
4970 if (!(t->flags & SN_ERR_MASK))
4971 t->flags |= SN_ERR_SRVTO;
4972 if (!(t->flags & SN_FINST_MASK))
4973 t->flags |= SN_FINST_D;
4974 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004975 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004976 /* write timeout */
4977 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004978 FD_CLR(t->srv_fd, StaticWriteEvent);
4979 tv_eternity(&t->swexpire);
4980 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004981 /* We must ensure that the read part is still alive when switching
4982 * to shutw */
4983 FD_SET(t->srv_fd, StaticReadEvent);
4984 if (t->proxy->srvtimeout)
4985 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004986 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004987 if (!(t->flags & SN_ERR_MASK))
4988 t->flags |= SN_ERR_SRVTO;
4989 if (!(t->flags & SN_FINST_MASK))
4990 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004991 return 1;
4992 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004993
4994 /* recompute request time-outs */
4995 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004996 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4997 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4998 tv_eternity(&t->swexpire);
4999 }
5000 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005001 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01005002 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5003 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005004 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005005 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005006 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5007 t->srexpire = t->swexpire;
5008 }
willy tarreau0f7af912005-12-17 12:21:26 +01005009 else
5010 tv_eternity(&t->swexpire);
5011 }
5012 }
5013
willy tarreaub1ff9db2005-12-17 13:51:03 +01005014 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01005015 if (rep->l == BUFSIZE) { /* no room to read more data */
5016 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5017 FD_CLR(t->srv_fd, StaticReadEvent);
5018 tv_eternity(&t->srexpire);
5019 }
5020 }
5021 else {
5022 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5023 FD_SET(t->srv_fd, StaticReadEvent);
5024 if (t->proxy->srvtimeout)
5025 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5026 else
5027 tv_eternity(&t->srexpire);
5028 }
5029 }
5030
5031 return 0; /* other cases change nothing */
5032 }
5033 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005034 if (t->res_sw == RES_ERROR) {
5035 //FD_CLR(t->srv_fd, StaticWriteEvent);
5036 tv_eternity(&t->swexpire);
5037 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005038 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005039 //close(t->srv_fd);
5040 t->srv_state = SV_STCLOSE;
5041 if (!(t->flags & SN_ERR_MASK))
5042 t->flags |= SN_ERR_SRVCL;
5043 if (!(t->flags & SN_FINST_MASK))
5044 t->flags |= SN_FINST_D;
5045 return 1;
5046 }
5047 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005048 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005049 tv_eternity(&t->swexpire);
5050 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005051 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005052 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005053 t->srv_state = SV_STCLOSE;
5054 return 1;
5055 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005056 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5057 //FD_CLR(t->srv_fd, StaticWriteEvent);
5058 tv_eternity(&t->swexpire);
5059 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005060 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005061 //close(t->srv_fd);
5062 t->srv_state = SV_STCLOSE;
5063 if (!(t->flags & SN_ERR_MASK))
5064 t->flags |= SN_ERR_SRVTO;
5065 if (!(t->flags & SN_FINST_MASK))
5066 t->flags |= SN_FINST_D;
5067 return 1;
5068 }
willy tarreau0f7af912005-12-17 12:21:26 +01005069 else if (req->l == 0) {
5070 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5071 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5072 tv_eternity(&t->swexpire);
5073 }
5074 }
5075 else { /* buffer not empty */
5076 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5077 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005078 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005079 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005080 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5081 t->srexpire = t->swexpire;
5082 }
willy tarreau0f7af912005-12-17 12:21:26 +01005083 else
5084 tv_eternity(&t->swexpire);
5085 }
5086 }
5087 return 0;
5088 }
5089 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005090 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005091 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005092 tv_eternity(&t->srexpire);
5093 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005094 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005095 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005096 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005097 if (!(t->flags & SN_ERR_MASK))
5098 t->flags |= SN_ERR_SRVCL;
5099 if (!(t->flags & SN_FINST_MASK))
5100 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005101 return 1;
5102 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005103 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5104 //FD_CLR(t->srv_fd, StaticReadEvent);
5105 tv_eternity(&t->srexpire);
5106 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005107 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005108 //close(t->srv_fd);
5109 t->srv_state = SV_STCLOSE;
5110 return 1;
5111 }
5112 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5113 //FD_CLR(t->srv_fd, StaticReadEvent);
5114 tv_eternity(&t->srexpire);
5115 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005116 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005117 //close(t->srv_fd);
5118 t->srv_state = SV_STCLOSE;
5119 if (!(t->flags & SN_ERR_MASK))
5120 t->flags |= SN_ERR_SRVTO;
5121 if (!(t->flags & SN_FINST_MASK))
5122 t->flags |= SN_FINST_D;
5123 return 1;
5124 }
willy tarreau0f7af912005-12-17 12:21:26 +01005125 else if (rep->l == BUFSIZE) { /* no room to read more data */
5126 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5127 FD_CLR(t->srv_fd, StaticReadEvent);
5128 tv_eternity(&t->srexpire);
5129 }
5130 }
5131 else {
5132 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5133 FD_SET(t->srv_fd, StaticReadEvent);
5134 if (t->proxy->srvtimeout)
5135 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5136 else
5137 tv_eternity(&t->srexpire);
5138 }
5139 }
5140 return 0;
5141 }
5142 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005143 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005144 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005145 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 +01005146 write(1, trash, len);
5147 }
5148 return 0;
5149 }
5150 return 0;
5151}
5152
5153
willy tarreau5cbea6f2005-12-17 12:48:26 +01005154/* Processes the client and server jobs of a session task, then
5155 * puts it back to the wait queue in a clean state, or
5156 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005157 * the time the task accepts to wait, or TIME_ETERNITY for
5158 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005159 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005160int process_session(struct task *t) {
5161 struct session *s = t->context;
5162 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005163
willy tarreau5cbea6f2005-12-17 12:48:26 +01005164 do {
5165 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005166 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005167 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005168 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005169 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005170 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005171 } while (fsm_resync);
5172
5173 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005174 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005175 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005176
willy tarreau5cbea6f2005-12-17 12:48:26 +01005177 tv_min(&min1, &s->crexpire, &s->cwexpire);
5178 tv_min(&min2, &s->srexpire, &s->swexpire);
5179 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005180 tv_min(&t->expire, &min1, &min2);
5181
5182 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005183 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005184
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005185#ifdef DEBUG_FULL
5186 /* DEBUG code : this should never ever happen, otherwise it indicates
5187 * that a task still has something to do and will provoke a quick loop.
5188 */
5189 if (tv_remain2(&now, &t->expire) <= 0)
5190 exit(100);
5191#endif
5192
willy tarreaub952e1d2005-12-18 01:31:20 +01005193 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005194 }
5195
willy tarreau5cbea6f2005-12-17 12:48:26 +01005196 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005197 actconn--;
5198
willy tarreau982249e2005-12-18 00:57:06 +01005199 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005200 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005201 len = sprintf(trash, "%08x:%s.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 +01005202 write(1, trash, len);
5203 }
5204
willy tarreau750a4722005-12-17 13:21:24 +01005205 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005206 if (s->rep != NULL)
5207 s->logs.bytes = s->rep->total;
5208
willy tarreau9fe663a2005-12-17 13:02:59 +01005209 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005210 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005211 sess_log(s);
5212
willy tarreau0f7af912005-12-17 12:21:26 +01005213 /* the task MUST not be in the run queue anymore */
5214 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005215 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005216 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005217 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005218}
5219
5220
5221
5222/*
5223 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005224 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005225 */
5226int process_chk(struct task *t) {
5227 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005228 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005229 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005230
willy tarreauef900ab2005-12-17 12:52:52 +01005231 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005232
willy tarreau25424f82006-03-19 19:37:48 +01005233 new_chk:
5234 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005235 if (fd < 0) { /* no check currently running */
5236 //fprintf(stderr, "process_chk: 2\n");
5237 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5238 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005239 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005240 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005241
5242 /* we don't send any health-checks when the proxy is stopped or when
5243 * the server should not be checked.
5244 */
5245 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005246 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5247 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005248 task_queue(t); /* restore t to its place in the task list */
5249 return tv_remain2(&now, &t->expire);
5250 }
5251
willy tarreau5cbea6f2005-12-17 12:48:26 +01005252 /* we'll initiate a new check */
5253 s->result = 0; /* no result yet */
5254 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005255 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005256 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5257 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5258 //fprintf(stderr, "process_chk: 3\n");
5259
willy tarreaua41a8b42005-12-17 14:02:24 +01005260 /* we'll connect to the check port on the server */
5261 sa = s->addr;
5262 sa.sin_port = htons(s->check_port);
5263
willy tarreau0174f312005-12-18 01:02:42 +01005264 /* allow specific binding :
5265 * - server-specific at first
5266 * - proxy-specific next
5267 */
5268 if (s->state & SRV_BIND_SRC) {
5269 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5270 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5271 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5272 s->proxy->id, s->id);
5273 s->result = -1;
5274 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005275 }
willy tarreau0174f312005-12-18 01:02:42 +01005276 else if (s->proxy->options & PR_O_BIND_SRC) {
5277 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5278 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5279 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5280 s->proxy->id);
5281 s->result = -1;
5282 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005283 }
willy tarreau0174f312005-12-18 01:02:42 +01005284
5285 if (!s->result) {
5286 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5287 /* OK, connection in progress or established */
5288
5289 //fprintf(stderr, "process_chk: 4\n");
5290
5291 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5292 fdtab[fd].owner = t;
5293 fdtab[fd].read = &event_srv_chk_r;
5294 fdtab[fd].write = &event_srv_chk_w;
5295 fdtab[fd].state = FD_STCONN; /* connection in progress */
5296 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005297#ifdef DEBUG_FULL
5298 assert (!FD_ISSET(fd, StaticReadEvent));
5299#endif
willy tarreau0174f312005-12-18 01:02:42 +01005300 fd_insert(fd);
5301 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5302 tv_delayfrom(&t->expire, &now, s->inter);
5303 task_queue(t); /* restore t to its place in the task list */
5304 return tv_remain(&now, &t->expire);
5305 }
5306 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5307 s->result = -1; /* a real error */
5308 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005309 }
5310 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005311 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005312 }
5313
5314 if (!s->result) { /* nothing done */
5315 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005316 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5317 tv_delayfrom(&t->expire, &t->expire, s->inter);
5318 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005319 }
5320
5321 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005322 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005323 s->health--; /* still good */
5324 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005325 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005326 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005327 recount_servers(s->proxy);
5328 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5329 s->state & SRV_BACKUP ? "Backup " : "",
5330 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5331 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5332 send_log(s->proxy, LOG_ALERT,
5333 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5334 s->state & SRV_BACKUP ? "Backup " : "",
5335 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5336 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreauef900ab2005-12-17 12:52:52 +01005337
willy tarreau62084d42006-03-24 18:57:41 +01005338 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
willy tarreaudd07e972005-12-18 00:48:48 +01005339 Alert("Proxy %s has no server available !\n", s->proxy->id);
5340 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5341 }
5342 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005343 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005344 }
5345
5346 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005347 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005348 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5349 tv_delayfrom(&t->expire, &t->expire, s->inter);
5350 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005351 }
5352 else {
5353 //fprintf(stderr, "process_chk: 8\n");
5354 /* there was a test running */
5355 if (s->result > 0) { /* good server detected */
5356 //fprintf(stderr, "process_chk: 9\n");
5357 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005358 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02005359 s->state |= SRV_RUNNING;
5360
willy tarreau535ae7a2005-12-17 12:58:00 +01005361 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005362 recount_servers(s->proxy);
5363 Warning("%sServer %s/%s UP. %d active and %d backup servers online.%s\n",
5364 s->state & SRV_BACKUP ? "Backup " : "",
5365 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5366 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5367 send_log(s->proxy, LOG_NOTICE,
5368 "%sServer %s/%s is UP. %d active and %d backup servers online.%s\n",
5369 s->state & SRV_BACKUP ? "Backup " : "",
5370 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5371 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreau535ae7a2005-12-17 12:58:00 +01005372 }
willy tarreauef900ab2005-12-17 12:52:52 +01005373
willy tarreaue47c8d72005-12-17 12:55:52 +01005374 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005375 }
willy tarreauef900ab2005-12-17 12:52:52 +01005376 s->curfd = -1; /* no check running anymore */
5377 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005378 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005379 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5380 tv_delayfrom(&t->expire, &t->expire, s->inter);
5381 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005382 }
5383 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5384 //fprintf(stderr, "process_chk: 10\n");
5385 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005386 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005387 s->health--; /* still good */
5388 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005389 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005390
willy tarreau62084d42006-03-24 18:57:41 +01005391 if (s->health == s->rise) {
5392 recount_servers(s->proxy);
5393 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5394 s->state & SRV_BACKUP ? "Backup " : "",
5395 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5396 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5397 send_log(s->proxy, LOG_ALERT,
5398 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5399 s->state & SRV_BACKUP ? "Backup " : "",
5400 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5401 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5402
5403 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5404 Alert("Proxy %s has no server available !\n", s->proxy->id);
5405 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5406 }
5407 }
willy tarreauef900ab2005-12-17 12:52:52 +01005408
willy tarreau5cbea6f2005-12-17 12:48:26 +01005409 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005410 }
5411 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005412 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005413 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005414 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5415 tv_delayfrom(&t->expire, &t->expire, s->inter);
5416 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005417 }
5418 /* if result is 0 and there's no timeout, we have to wait again */
5419 }
5420 //fprintf(stderr, "process_chk: 11\n");
5421 s->result = 0;
5422 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005423 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005424}
5425
5426
willy tarreau5cbea6f2005-12-17 12:48:26 +01005427
willy tarreau0f7af912005-12-17 12:21:26 +01005428#if STATTIME > 0
5429int stats(void);
5430#endif
5431
5432/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005433 * This does 4 things :
5434 * - wake up all expired tasks
5435 * - call all runnable tasks
5436 * - call maintain_proxies() to enable/disable the listeners
5437 * - return the delay till next event in ms, -1 = wait indefinitely
5438 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5439 *
willy tarreau0f7af912005-12-17 12:21:26 +01005440 */
5441
willy tarreau1c2ad212005-12-18 01:11:29 +01005442int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005443 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005444 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005445 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005446
willy tarreaub952e1d2005-12-18 01:31:20 +01005447 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005448
willy tarreau1c2ad212005-12-18 01:11:29 +01005449 /* look for expired tasks and add them to the run queue.
5450 */
5451 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5452 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5453 tnext = t->next;
5454 if (t->state & TASK_RUNNING)
5455 continue;
5456
willy tarreaub952e1d2005-12-18 01:31:20 +01005457 if (tv_iseternity(&t->expire))
5458 continue;
5459
willy tarreau1c2ad212005-12-18 01:11:29 +01005460 /* wakeup expired entries. It doesn't matter if they are
5461 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005462 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005463 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005464 task_wakeup(&rq, t);
5465 }
5466 else {
5467 /* first non-runnable task. Use its expiration date as an upper bound */
5468 int temp_time = tv_remain(&now, &t->expire);
5469 if (temp_time)
5470 next_time = temp_time;
5471 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005472 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005473 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005474
willy tarreau1c2ad212005-12-18 01:11:29 +01005475 /* process each task in the run queue now. Each task may be deleted
5476 * since we only use tnext.
5477 */
5478 tnext = rq;
5479 while ((t = tnext) != NULL) {
5480 int temp_time;
5481
5482 tnext = t->rqnext;
5483 task_sleep(&rq, t);
5484 temp_time = t->process(t);
5485 next_time = MINTIME(temp_time, next_time);
5486 }
5487
5488 /* maintain all proxies in a consistent state. This should quickly become a task */
5489 time2 = maintain_proxies();
5490 return MINTIME(time2, next_time);
5491}
5492
5493
5494#if defined(ENABLE_EPOLL)
5495
5496/*
5497 * Main epoll() loop.
5498 */
5499
5500/* does 3 actions :
5501 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5502 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5503 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5504 *
5505 * returns 0 if initialization failed, !0 otherwise.
5506 */
5507
5508int epoll_loop(int action) {
5509 int next_time;
5510 int status;
5511 int fd;
5512
5513 int fds, count;
5514 int pr, pw, sr, sw;
5515 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5516 struct epoll_event ev;
5517
5518 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005519 static struct epoll_event *epoll_events = NULL;
5520 static int epoll_fd;
5521
5522 if (action == POLL_LOOP_ACTION_INIT) {
5523 epoll_fd = epoll_create(global.maxsock + 1);
5524 if (epoll_fd < 0)
5525 return 0;
5526 else {
5527 epoll_events = (struct epoll_event*)
5528 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5529 PrevReadEvent = (fd_set *)
5530 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5531 PrevWriteEvent = (fd_set *)
5532 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005533 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005534 return 1;
5535 }
5536 else if (action == POLL_LOOP_ACTION_CLEAN) {
5537 if (PrevWriteEvent) free(PrevWriteEvent);
5538 if (PrevReadEvent) free(PrevReadEvent);
5539 if (epoll_events) free(epoll_events);
5540 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005541 epoll_fd = 0;
5542 return 1;
5543 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005544
willy tarreau1c2ad212005-12-18 01:11:29 +01005545 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005546
willy tarreau1c2ad212005-12-18 01:11:29 +01005547 tv_now(&now);
5548
5549 while (1) {
5550 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005551
5552 /* stop when there's no connection left and we don't allow them anymore */
5553 if (!actconn && listeners == 0)
5554 break;
5555
willy tarreau0f7af912005-12-17 12:21:26 +01005556#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005557 {
5558 int time2;
5559 time2 = stats();
5560 next_time = MINTIME(time2, next_time);
5561 }
willy tarreau0f7af912005-12-17 12:21:26 +01005562#endif
5563
willy tarreau1c2ad212005-12-18 01:11:29 +01005564 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5565
5566 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5567 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5568
5569 if ((ro^rn) | (wo^wn)) {
5570 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5571#define FDSETS_ARE_INT_ALIGNED
5572#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005573
willy tarreauad90a0c2005-12-18 01:09:15 +01005574#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5575#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005576 pr = (ro >> count) & 1;
5577 pw = (wo >> count) & 1;
5578 sr = (rn >> count) & 1;
5579 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005580#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005581 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5582 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5583 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5584 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005585#endif
5586#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005587 pr = FD_ISSET(fd, PrevReadEvent);
5588 pw = FD_ISSET(fd, PrevWriteEvent);
5589 sr = FD_ISSET(fd, StaticReadEvent);
5590 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005591#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005592 if (!((sr^pr) | (sw^pw)))
5593 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005594
willy tarreau1c2ad212005-12-18 01:11:29 +01005595 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5596 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005597
willy tarreaub952e1d2005-12-18 01:31:20 +01005598#ifdef EPOLL_CTL_MOD_WORKAROUND
5599 /* I encountered a rarely reproducible problem with
5600 * EPOLL_CTL_MOD where a modified FD (systematically
5601 * the one in epoll_events[0], fd#7) would sometimes
5602 * be set EPOLL_OUT while asked for a read ! This is
5603 * with the 2.4 epoll patch. The workaround is to
5604 * delete then recreate in case of modification.
5605 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5606 * nor RHEL kernels.
5607 */
5608
5609 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5610 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5611
5612 if ((sr | sw))
5613 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5614#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005615 if ((pr | pw)) {
5616 /* the file-descriptor already exists... */
5617 if ((sr | sw)) {
5618 /* ...and it will still exist */
5619 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5620 // perror("epoll_ctl(MOD)");
5621 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005622 }
5623 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005624 /* ...and it will be removed */
5625 if (fdtab[fd].state != FD_STCLOSE &&
5626 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5627 // perror("epoll_ctl(DEL)");
5628 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005629 }
5630 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005631 } else {
5632 /* the file-descriptor did not exist, let's add it */
5633 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5634 // perror("epoll_ctl(ADD)");
5635 // exit(1);
5636 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005637 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005638#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005639 }
5640 ((int*)PrevReadEvent)[fds] = rn;
5641 ((int*)PrevWriteEvent)[fds] = wn;
5642 }
5643 }
5644
5645 /* now let's wait for events */
5646 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5647 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005648
willy tarreau1c2ad212005-12-18 01:11:29 +01005649 for (count = 0; count < status; count++) {
5650 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01005651
5652 if (FD_ISSET(fd, StaticReadEvent)) {
5653 if (fdtab[fd].state == FD_STCLOSE)
5654 continue;
5655 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5656 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005657 }
willy tarreau05be12b2006-03-19 19:35:00 +01005658
5659 if (FD_ISSET(fd, StaticWriteEvent)) {
5660 if (fdtab[fd].state == FD_STCLOSE)
5661 continue;
5662 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5663 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005664 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005665 }
5666 }
5667 return 1;
5668}
5669#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005670
willy tarreauad90a0c2005-12-18 01:09:15 +01005671
willy tarreau5cbea6f2005-12-17 12:48:26 +01005672
willy tarreau1c2ad212005-12-18 01:11:29 +01005673#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005674
willy tarreau1c2ad212005-12-18 01:11:29 +01005675/*
5676 * Main poll() loop.
5677 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005678
willy tarreau1c2ad212005-12-18 01:11:29 +01005679/* does 3 actions :
5680 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5681 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5682 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5683 *
5684 * returns 0 if initialization failed, !0 otherwise.
5685 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005686
willy tarreau1c2ad212005-12-18 01:11:29 +01005687int poll_loop(int action) {
5688 int next_time;
5689 int status;
5690 int fd, nbfd;
5691
5692 int fds, count;
5693 int sr, sw;
5694 unsigned rn, wn; /* read new, write new */
5695
5696 /* private data */
5697 static struct pollfd *poll_events = NULL;
5698
5699 if (action == POLL_LOOP_ACTION_INIT) {
5700 poll_events = (struct pollfd*)
5701 calloc(1, sizeof(struct pollfd) * global.maxsock);
5702 return 1;
5703 }
5704 else if (action == POLL_LOOP_ACTION_CLEAN) {
5705 if (poll_events)
5706 free(poll_events);
5707 return 1;
5708 }
5709
5710 /* OK, it's POLL_LOOP_ACTION_RUN */
5711
5712 tv_now(&now);
5713
5714 while (1) {
5715 next_time = process_runnable_tasks();
5716
5717 /* stop when there's no connection left and we don't allow them anymore */
5718 if (!actconn && listeners == 0)
5719 break;
5720
5721#if STATTIME > 0
5722 {
5723 int time2;
5724 time2 = stats();
5725 next_time = MINTIME(time2, next_time);
5726 }
5727#endif
5728
5729
5730 nbfd = 0;
5731 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5732
5733 rn = ((int*)StaticReadEvent)[fds];
5734 wn = ((int*)StaticWriteEvent)[fds];
5735
5736 if ((rn|wn)) {
5737 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5738#define FDSETS_ARE_INT_ALIGNED
5739#ifdef FDSETS_ARE_INT_ALIGNED
5740
5741#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5742#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5743 sr = (rn >> count) & 1;
5744 sw = (wn >> count) & 1;
5745#else
5746 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5747 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5748#endif
5749#else
5750 sr = FD_ISSET(fd, StaticReadEvent);
5751 sw = FD_ISSET(fd, StaticWriteEvent);
5752#endif
5753 if ((sr|sw)) {
5754 poll_events[nbfd].fd = fd;
5755 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5756 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005757 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005758 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005759 }
5760 }
5761
5762 /* now let's wait for events */
5763 status = poll(poll_events, nbfd, next_time);
5764 tv_now(&now);
5765
5766 for (count = 0; status > 0 && count < nbfd; count++) {
5767 fd = poll_events[count].fd;
5768
5769 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5770 continue;
5771
5772 /* ok, we found one active fd */
5773 status--;
5774
willy tarreau05be12b2006-03-19 19:35:00 +01005775 if (FD_ISSET(fd, StaticReadEvent)) {
5776 if (fdtab[fd].state == FD_STCLOSE)
5777 continue;
5778 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5779 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005780 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005781
willy tarreau05be12b2006-03-19 19:35:00 +01005782 if (FD_ISSET(fd, StaticWriteEvent)) {
5783 if (fdtab[fd].state == FD_STCLOSE)
5784 continue;
5785 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5786 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005787 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005788 }
5789 }
5790 return 1;
5791}
willy tarreauad90a0c2005-12-18 01:09:15 +01005792#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005793
willy tarreauad90a0c2005-12-18 01:09:15 +01005794
willy tarreauad90a0c2005-12-18 01:09:15 +01005795
willy tarreau1c2ad212005-12-18 01:11:29 +01005796/*
5797 * Main select() loop.
5798 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005799
willy tarreau1c2ad212005-12-18 01:11:29 +01005800/* does 3 actions :
5801 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5802 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5803 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5804 *
5805 * returns 0 if initialization failed, !0 otherwise.
5806 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005807
willy tarreauad90a0c2005-12-18 01:09:15 +01005808
willy tarreau1c2ad212005-12-18 01:11:29 +01005809int select_loop(int action) {
5810 int next_time;
5811 int status;
5812 int fd,i;
5813 struct timeval delta;
5814 int readnotnull, writenotnull;
5815 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005816
willy tarreau1c2ad212005-12-18 01:11:29 +01005817 if (action == POLL_LOOP_ACTION_INIT) {
5818 ReadEvent = (fd_set *)
5819 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5820 WriteEvent = (fd_set *)
5821 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5822 return 1;
5823 }
5824 else if (action == POLL_LOOP_ACTION_CLEAN) {
5825 if (WriteEvent) free(WriteEvent);
5826 if (ReadEvent) free(ReadEvent);
5827 return 1;
5828 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005829
willy tarreau1c2ad212005-12-18 01:11:29 +01005830 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005831
willy tarreau1c2ad212005-12-18 01:11:29 +01005832 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005833
willy tarreau1c2ad212005-12-18 01:11:29 +01005834 while (1) {
5835 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005836
willy tarreau1c2ad212005-12-18 01:11:29 +01005837 /* stop when there's no connection left and we don't allow them anymore */
5838 if (!actconn && listeners == 0)
5839 break;
5840
5841#if STATTIME > 0
5842 {
5843 int time2;
5844 time2 = stats();
5845 next_time = MINTIME(time2, next_time);
5846 }
5847#endif
5848
willy tarreau1c2ad212005-12-18 01:11:29 +01005849 if (next_time > 0) { /* FIXME */
5850 /* Convert to timeval */
5851 /* to avoid eventual select loops due to timer precision */
5852 next_time += SCHEDULER_RESOLUTION;
5853 delta.tv_sec = next_time / 1000;
5854 delta.tv_usec = (next_time % 1000) * 1000;
5855 }
5856 else if (next_time == 0) { /* allow select to return immediately when needed */
5857 delta.tv_sec = delta.tv_usec = 0;
5858 }
5859
5860
5861 /* let's restore fdset state */
5862
5863 readnotnull = 0; writenotnull = 0;
5864 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5865 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5866 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5867 }
5868
5869 // /* just a verification code, needs to be removed for performance */
5870 // for (i=0; i<maxfd; i++) {
5871 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5872 // abort();
5873 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5874 // abort();
5875 //
5876 // }
5877
5878 status = select(maxfd,
5879 readnotnull ? ReadEvent : NULL,
5880 writenotnull ? WriteEvent : NULL,
5881 NULL,
5882 (next_time >= 0) ? &delta : NULL);
5883
5884 /* this is an experiment on the separation of the select work */
5885 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5886 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5887
5888 tv_now(&now);
5889
5890 if (status > 0) { /* must proceed with events */
5891
5892 int fds;
5893 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005894
willy tarreau1c2ad212005-12-18 01:11:29 +01005895 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5896 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5897 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5898
5899 /* if we specify read first, the accepts and zero reads will be
5900 * seen first. Moreover, system buffers will be flushed faster.
5901 */
willy tarreau05be12b2006-03-19 19:35:00 +01005902 if (FD_ISSET(fd, ReadEvent)) {
5903 if (fdtab[fd].state == FD_STCLOSE)
5904 continue;
5905 fdtab[fd].read(fd);
5906 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005907
willy tarreau05be12b2006-03-19 19:35:00 +01005908 if (FD_ISSET(fd, WriteEvent)) {
5909 if (fdtab[fd].state == FD_STCLOSE)
5910 continue;
5911 fdtab[fd].write(fd);
5912 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005913 }
5914 }
5915 else {
5916 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005917 }
willy tarreau0f7af912005-12-17 12:21:26 +01005918 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005919 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005920}
5921
5922
5923#if STATTIME > 0
5924/*
5925 * Display proxy statistics regularly. It is designed to be called from the
5926 * select_loop().
5927 */
5928int stats(void) {
5929 static int lines;
5930 static struct timeval nextevt;
5931 static struct timeval lastevt;
5932 static struct timeval starttime = {0,0};
5933 unsigned long totaltime, deltatime;
5934 int ret;
5935
willy tarreau750a4722005-12-17 13:21:24 +01005936 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005937 deltatime = (tv_diff(&lastevt, &now)?:1);
5938 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005939
willy tarreau9fe663a2005-12-17 13:02:59 +01005940 if (global.mode & MODE_STATS) {
5941 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005942 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005943 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5944 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005945 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005946 actconn, totalconn,
5947 stats_tsk_new, stats_tsk_good,
5948 stats_tsk_left, stats_tsk_right,
5949 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5950 }
5951 }
5952
5953 tv_delayfrom(&nextevt, &now, STATTIME);
5954
5955 lastevt=now;
5956 }
5957 ret = tv_remain(&now, &nextevt);
5958 return ret;
5959}
5960#endif
5961
5962
5963/*
5964 * this function enables proxies when there are enough free sessions,
5965 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005966 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005967 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005968 */
5969static int maintain_proxies(void) {
5970 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005971 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005972 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005973
5974 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005975 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005976
5977 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005978 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005979 while (p) {
5980 if (p->nbconn < p->maxconn) {
5981 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005982 for (l = p->listen; l != NULL; l = l->next) {
5983 FD_SET(l->fd, StaticReadEvent);
5984 }
willy tarreau0f7af912005-12-17 12:21:26 +01005985 p->state = PR_STRUN;
5986 }
5987 }
5988 else {
5989 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005990 for (l = p->listen; l != NULL; l = l->next) {
5991 FD_CLR(l->fd, StaticReadEvent);
5992 }
willy tarreau0f7af912005-12-17 12:21:26 +01005993 p->state = PR_STIDLE;
5994 }
5995 }
5996 p = p->next;
5997 }
5998 }
5999 else { /* block all proxies */
6000 while (p) {
6001 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006002 for (l = p->listen; l != NULL; l = l->next) {
6003 FD_CLR(l->fd, StaticReadEvent);
6004 }
willy tarreau0f7af912005-12-17 12:21:26 +01006005 p->state = PR_STIDLE;
6006 }
6007 p = p->next;
6008 }
6009 }
6010
willy tarreau5cbea6f2005-12-17 12:48:26 +01006011 if (stopping) {
6012 p = proxy;
6013 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01006014 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006015 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006016 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006017 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006018 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006019 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006020
willy tarreaua41a8b42005-12-17 14:02:24 +01006021 for (l = p->listen; l != NULL; l = l->next) {
6022 fd_delete(l->fd);
6023 listeners--;
6024 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006025 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006026 }
6027 else {
6028 tleft = MINTIME(t, tleft);
6029 }
6030 }
6031 p = p->next;
6032 }
6033 }
6034 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006035}
6036
6037/*
6038 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006039 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6040 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006041 */
6042static void soft_stop(void) {
6043 struct proxy *p;
6044
6045 stopping = 1;
6046 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006047 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006048 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006049 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006050 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006051 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006052 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006053 }
willy tarreau0f7af912005-12-17 12:21:26 +01006054 p = p->next;
6055 }
6056}
6057
willy tarreaudbd3bef2006-01-20 19:35:18 +01006058static void pause_proxy(struct proxy *p) {
6059 struct listener *l;
6060 for (l = p->listen; l != NULL; l = l->next) {
6061 shutdown(l->fd, SHUT_RD);
6062 FD_CLR(l->fd, StaticReadEvent);
6063 p->state = PR_STPAUSED;
6064 }
6065}
6066
6067/*
6068 * This function temporarily disables listening so that another new instance
6069 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006070 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006071 * the proxy, or a SIGTTIN can be sent to listen again.
6072 */
6073static void pause_proxies(void) {
6074 struct proxy *p;
6075
6076 p = proxy;
6077 tv_now(&now); /* else, the old time before select will be used */
6078 while (p) {
6079 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6080 Warning("Pausing proxy %s.\n", p->id);
6081 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6082 pause_proxy(p);
6083 }
6084 p = p->next;
6085 }
6086}
6087
6088
6089/*
6090 * This function reactivates listening. This can be used after a call to
6091 * sig_pause(), for example when a new instance has failed starting up.
6092 * It is designed to be called upon reception of a SIGTTIN.
6093 */
6094static void listen_proxies(void) {
6095 struct proxy *p;
6096 struct listener *l;
6097
6098 p = proxy;
6099 tv_now(&now); /* else, the old time before select will be used */
6100 while (p) {
6101 if (p->state == PR_STPAUSED) {
6102 Warning("Enabling proxy %s.\n", p->id);
6103 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6104
6105 for (l = p->listen; l != NULL; l = l->next) {
6106 if (listen(l->fd, p->maxconn) == 0) {
6107 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6108 FD_SET(l->fd, StaticReadEvent);
6109 p->state = PR_STRUN;
6110 }
6111 else
6112 p->state = PR_STIDLE;
6113 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006114 int port;
6115
6116 if (l->addr.ss_family == AF_INET6)
6117 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6118 else
6119 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6120
willy tarreaudbd3bef2006-01-20 19:35:18 +01006121 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006122 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006123 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006124 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006125 /* Another port might have been enabled. Let's stop everything. */
6126 pause_proxy(p);
6127 break;
6128 }
6129 }
6130 }
6131 p = p->next;
6132 }
6133}
6134
6135
willy tarreau0f7af912005-12-17 12:21:26 +01006136/*
6137 * upon SIGUSR1, let's have a soft stop.
6138 */
6139void sig_soft_stop(int sig) {
6140 soft_stop();
6141 signal(sig, SIG_IGN);
6142}
6143
willy tarreaudbd3bef2006-01-20 19:35:18 +01006144/*
6145 * upon SIGTTOU, we pause everything
6146 */
6147void sig_pause(int sig) {
6148 pause_proxies();
6149 signal(sig, sig_pause);
6150}
willy tarreau0f7af912005-12-17 12:21:26 +01006151
willy tarreau8337c6b2005-12-17 13:41:01 +01006152/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006153 * upon SIGTTIN, let's have a soft stop.
6154 */
6155void sig_listen(int sig) {
6156 listen_proxies();
6157 signal(sig, sig_listen);
6158}
6159
6160/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006161 * this function dumps every server's state when the process receives SIGHUP.
6162 */
6163void sig_dump_state(int sig) {
6164 struct proxy *p = proxy;
6165
6166 Warning("SIGHUP received, dumping servers states.\n");
6167 while (p) {
6168 struct server *s = p->srv;
6169
6170 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
6171 while (s) {
6172 if (s->state & SRV_RUNNING) {
willy tarreaufd6dfe72006-03-19 19:38:19 +01006173 Warning("SIGHUP: Server %s/%s is UP.\n", p->id, s->id);
6174 send_log(p, LOG_NOTICE, "SIGUP: Server %s/%s is UP.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006175 }
6176 else {
willy tarreaufd6dfe72006-03-19 19:38:19 +01006177 Warning("SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
6178 send_log(p, LOG_NOTICE, "SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006179 }
6180 s = s->next;
6181 }
willy tarreaudd07e972005-12-18 00:48:48 +01006182
willy tarreau62084d42006-03-24 18:57:41 +01006183 if (p->srv_act == 0) {
6184 if (p->srv_bck) {
6185 Warning("SIGHUP: Proxy %s is running on backup servers !\n", p->id);
6186 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s is running on backup servers !\n", p->id);
6187 } else {
6188 Warning("SIGHUP: Proxy %s has no server available !\n", p->id);
6189 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s has no server available !\n", p->id);
6190 }
6191 }
willy tarreaudd07e972005-12-18 00:48:48 +01006192
willy tarreau8337c6b2005-12-17 13:41:01 +01006193 p = p->next;
6194 }
6195 signal(sig, sig_dump_state);
6196}
6197
willy tarreau0f7af912005-12-17 12:21:26 +01006198void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006199 struct task *t, *tnext;
6200 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006201
willy tarreau5cbea6f2005-12-17 12:48:26 +01006202 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
6203 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
6204 tnext = t->next;
6205 s = t->context;
6206 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6207 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6208 "req=%d, rep=%d, clifd=%d\n",
6209 s, tv_remain(&now, &t->expire),
6210 s->cli_state,
6211 s->srv_state,
6212 FD_ISSET(s->cli_fd, StaticReadEvent),
6213 FD_ISSET(s->cli_fd, StaticWriteEvent),
6214 FD_ISSET(s->srv_fd, StaticReadEvent),
6215 FD_ISSET(s->srv_fd, StaticWriteEvent),
6216 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6217 );
willy tarreau0f7af912005-12-17 12:21:26 +01006218 }
willy tarreau12350152005-12-18 01:03:27 +01006219}
6220
willy tarreau64a3cc32005-12-18 01:13:11 +01006221#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006222static void fast_stop(void)
6223{
6224 struct proxy *p;
6225 p = proxy;
6226 while (p) {
6227 p->grace = 0;
6228 p = p->next;
6229 }
6230 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006231}
6232
willy tarreau12350152005-12-18 01:03:27 +01006233void sig_int(int sig) {
6234 /* This would normally be a hard stop,
6235 but we want to be sure about deallocation,
6236 and so on, so we do a soft stop with
6237 0 GRACE time
6238 */
6239 fast_stop();
6240 /* If we are killed twice, we decide to die*/
6241 signal(sig, SIG_DFL);
6242}
6243
6244void sig_term(int sig) {
6245 /* This would normally be a hard stop,
6246 but we want to be sure about deallocation,
6247 and so on, so we do a soft stop with
6248 0 GRACE time
6249 */
6250 fast_stop();
6251 /* If we are killed twice, we decide to die*/
6252 signal(sig, SIG_DFL);
6253}
willy tarreau64a3cc32005-12-18 01:13:11 +01006254#endif
willy tarreau12350152005-12-18 01:03:27 +01006255
willy tarreauc1f47532005-12-18 01:08:26 +01006256/* returns the pointer to an error in the replacement string, or NULL if OK */
6257char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006258 struct hdr_exp *exp;
6259
willy tarreauc1f47532005-12-18 01:08:26 +01006260 if (replace != NULL) {
6261 char *err;
6262 err = check_replace_string(replace);
6263 if (err)
6264 return err;
6265 }
6266
willy tarreaue39cd132005-12-17 13:00:18 +01006267 while (*head != NULL)
6268 head = &(*head)->next;
6269
6270 exp = calloc(1, sizeof(struct hdr_exp));
6271
6272 exp->preg = preg;
6273 exp->replace = replace;
6274 exp->action = action;
6275 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006276
6277 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006278}
6279
willy tarreau9fe663a2005-12-17 13:02:59 +01006280
willy tarreau0f7af912005-12-17 12:21:26 +01006281/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006282 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006283 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006284int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006285
willy tarreau9fe663a2005-12-17 13:02:59 +01006286 if (!strcmp(args[0], "global")) { /* new section */
6287 /* no option, nothing special to do */
6288 return 0;
6289 }
6290 else if (!strcmp(args[0], "daemon")) {
6291 global.mode |= MODE_DAEMON;
6292 }
6293 else if (!strcmp(args[0], "debug")) {
6294 global.mode |= MODE_DEBUG;
6295 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006296 else if (!strcmp(args[0], "noepoll")) {
6297 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6298 }
6299 else if (!strcmp(args[0], "nopoll")) {
6300 cfg_polling_mechanism &= ~POLL_USE_POLL;
6301 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006302 else if (!strcmp(args[0], "quiet")) {
6303 global.mode |= MODE_QUIET;
6304 }
6305 else if (!strcmp(args[0], "stats")) {
6306 global.mode |= MODE_STATS;
6307 }
6308 else if (!strcmp(args[0], "uid")) {
6309 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006310 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006311 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006312 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006313 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006314 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006315 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006316 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006317 global.uid = atol(args[1]);
6318 }
6319 else if (!strcmp(args[0], "gid")) {
6320 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006321 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006322 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006323 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006324 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006325 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006326 return -1;
6327 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006328 global.gid = atol(args[1]);
6329 }
6330 else if (!strcmp(args[0], "nbproc")) {
6331 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006332 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006333 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006334 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006335 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006336 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006337 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006338 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006339 global.nbproc = atol(args[1]);
6340 }
6341 else if (!strcmp(args[0], "maxconn")) {
6342 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006343 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006344 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006345 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006346 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006347 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006348 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006349 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006350 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006351#ifdef SYSTEM_MAXCONN
6352 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6353 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);
6354 global.maxconn = DEFAULT_MAXCONN;
6355 }
6356#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006357 }
willy tarreaub1285d52005-12-18 01:20:14 +01006358 else if (!strcmp(args[0], "ulimit-n")) {
6359 if (global.rlimit_nofile != 0) {
6360 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6361 return 0;
6362 }
6363 if (*(args[1]) == 0) {
6364 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6365 return -1;
6366 }
6367 global.rlimit_nofile = atol(args[1]);
6368 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006369 else if (!strcmp(args[0], "chroot")) {
6370 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006371 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006372 return 0;
6373 }
6374 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006375 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006376 return -1;
6377 }
6378 global.chroot = strdup(args[1]);
6379 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006380 else if (!strcmp(args[0], "pidfile")) {
6381 if (global.pidfile != NULL) {
6382 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6383 return 0;
6384 }
6385 if (*(args[1]) == 0) {
6386 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6387 return -1;
6388 }
6389 global.pidfile = strdup(args[1]);
6390 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006391 else if (!strcmp(args[0], "log")) { /* syslog server address */
6392 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006393 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006394
6395 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006396 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006397 return -1;
6398 }
6399
6400 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6401 if (!strcmp(log_facilities[facility], args[2]))
6402 break;
6403
6404 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006405 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006406 exit(1);
6407 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006408
6409 level = 7; /* max syslog level = debug */
6410 if (*(args[3])) {
6411 while (level >= 0 && strcmp(log_levels[level], args[3]))
6412 level--;
6413 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006414 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006415 exit(1);
6416 }
6417 }
6418
willy tarreau9fe663a2005-12-17 13:02:59 +01006419 sa = str2sa(args[1]);
6420 if (!sa->sin_port)
6421 sa->sin_port = htons(SYSLOG_PORT);
6422
6423 if (global.logfac1 == -1) {
6424 global.logsrv1 = *sa;
6425 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006426 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006427 }
6428 else if (global.logfac2 == -1) {
6429 global.logsrv2 = *sa;
6430 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006431 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006432 }
6433 else {
6434 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6435 return -1;
6436 }
6437
6438 }
6439 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006440 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006441 return -1;
6442 }
6443 return 0;
6444}
6445
6446
willy tarreaua41a8b42005-12-17 14:02:24 +01006447void init_default_instance() {
6448 memset(&defproxy, 0, sizeof(defproxy));
6449 defproxy.mode = PR_MODE_TCP;
6450 defproxy.state = PR_STNEW;
6451 defproxy.maxconn = cfg_maxpconn;
6452 defproxy.conn_retries = CONN_RETRIES;
6453 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6454}
6455
willy tarreau9fe663a2005-12-17 13:02:59 +01006456/*
6457 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6458 */
6459int cfg_parse_listen(char *file, int linenum, char **args) {
6460 static struct proxy *curproxy = NULL;
6461 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006462 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006463 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006464
6465 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006466 if (!*args[1]) {
6467 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6468 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006469 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006470 return -1;
6471 }
6472
6473 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006474 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006475 return -1;
6476 }
6477 curproxy->next = proxy;
6478 proxy = curproxy;
6479 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006480
6481 /* parse the listener address if any */
6482 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006483 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006484 if (!curproxy->listen)
6485 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006486 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01006487 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006488
willy tarreau9fe663a2005-12-17 13:02:59 +01006489 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006490 curproxy->state = defproxy.state;
6491 curproxy->maxconn = defproxy.maxconn;
6492 curproxy->conn_retries = defproxy.conn_retries;
6493 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006494
6495 if (defproxy.check_req)
6496 curproxy->check_req = strdup(defproxy.check_req);
6497 curproxy->check_len = defproxy.check_len;
6498
6499 if (defproxy.cookie_name)
6500 curproxy->cookie_name = strdup(defproxy.cookie_name);
6501 curproxy->cookie_len = defproxy.cookie_len;
6502
6503 if (defproxy.capture_name)
6504 curproxy->capture_name = strdup(defproxy.capture_name);
6505 curproxy->capture_namelen = defproxy.capture_namelen;
6506 curproxy->capture_len = defproxy.capture_len;
6507
6508 if (defproxy.errmsg.msg400)
6509 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6510 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6511
6512 if (defproxy.errmsg.msg403)
6513 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6514 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6515
6516 if (defproxy.errmsg.msg408)
6517 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6518 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6519
6520 if (defproxy.errmsg.msg500)
6521 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6522 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6523
6524 if (defproxy.errmsg.msg502)
6525 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6526 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6527
6528 if (defproxy.errmsg.msg503)
6529 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6530 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6531
6532 if (defproxy.errmsg.msg504)
6533 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6534 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6535
willy tarreaua41a8b42005-12-17 14:02:24 +01006536 curproxy->clitimeout = defproxy.clitimeout;
6537 curproxy->contimeout = defproxy.contimeout;
6538 curproxy->srvtimeout = defproxy.srvtimeout;
6539 curproxy->mode = defproxy.mode;
6540 curproxy->logfac1 = defproxy.logfac1;
6541 curproxy->logsrv1 = defproxy.logsrv1;
6542 curproxy->loglev1 = defproxy.loglev1;
6543 curproxy->logfac2 = defproxy.logfac2;
6544 curproxy->logsrv2 = defproxy.logsrv2;
6545 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006546 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006547 curproxy->grace = defproxy.grace;
6548 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006549 curproxy->mon_net = defproxy.mon_net;
6550 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006551 return 0;
6552 }
6553 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006554 /* some variables may have already been initialized earlier */
6555 if (defproxy.check_req) free(defproxy.check_req);
6556 if (defproxy.cookie_name) free(defproxy.cookie_name);
6557 if (defproxy.capture_name) free(defproxy.capture_name);
6558 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6559 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6560 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6561 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6562 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6563 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6564 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6565
6566 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006567 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006568 return 0;
6569 }
6570 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006571 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006572 return -1;
6573 }
6574
willy tarreaua41a8b42005-12-17 14:02:24 +01006575 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6576 if (curproxy == &defproxy) {
6577 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6578 return -1;
6579 }
6580
6581 if (strchr(args[1], ':') == NULL) {
6582 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6583 file, linenum, args[0]);
6584 return -1;
6585 }
6586 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006587 if (!curproxy->listen)
6588 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006589 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006590 return 0;
6591 }
willy tarreaub1285d52005-12-18 01:20:14 +01006592 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6593 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6594 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6595 file, linenum, args[0]);
6596 return -1;
6597 }
6598 /* flush useless bits */
6599 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6600 return 0;
6601 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006602 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006603 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6604 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6605 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6606 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006607 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006608 return -1;
6609 }
6610 }
6611 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006612 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006613 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006614 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6615 curproxy->state = PR_STNEW;
6616 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006617 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6618 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006619// if (curproxy == &defproxy) {
6620// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6621// return -1;
6622// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006623
willy tarreau9fe663a2005-12-17 13:02:59 +01006624 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006625// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6626// file, linenum);
6627// return 0;
6628 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006629 }
6630
6631 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006632 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6633 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006634 return -1;
6635 }
6636 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006637 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006638
6639 cur_arg = 2;
6640 while (*(args[cur_arg])) {
6641 if (!strcmp(args[cur_arg], "rewrite")) {
6642 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006643 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006644 else if (!strcmp(args[cur_arg], "indirect")) {
6645 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006646 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006647 else if (!strcmp(args[cur_arg], "insert")) {
6648 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006649 }
willy tarreau240afa62005-12-17 13:14:35 +01006650 else if (!strcmp(args[cur_arg], "nocache")) {
6651 curproxy->options |= PR_O_COOK_NOC;
6652 }
willy tarreaucd878942005-12-17 13:27:43 +01006653 else if (!strcmp(args[cur_arg], "postonly")) {
6654 curproxy->options |= PR_O_COOK_POST;
6655 }
willy tarreau0174f312005-12-18 01:02:42 +01006656 else if (!strcmp(args[cur_arg], "prefix")) {
6657 curproxy->options |= PR_O_COOK_PFX;
6658 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006659 else {
willy tarreau0174f312005-12-18 01:02:42 +01006660 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006661 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006662 return -1;
6663 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006664 cur_arg++;
6665 }
willy tarreau0174f312005-12-18 01:02:42 +01006666 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6667 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6668 file, linenum);
6669 return -1;
6670 }
6671
6672 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6673 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006674 file, linenum);
6675 return -1;
6676 }
willy tarreau12350152005-12-18 01:03:27 +01006677 }/* end else if (!strcmp(args[0], "cookie")) */
6678 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6679// if (curproxy == &defproxy) {
6680// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6681// return -1;
6682// }
6683
6684 if (curproxy->appsession_name != NULL) {
6685// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6686// file, linenum);
6687// return 0;
6688 free(curproxy->appsession_name);
6689 }
6690
6691 if (*(args[5]) == 0) {
6692 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6693 file, linenum, args[0]);
6694 return -1;
6695 }
6696 have_appsession = 1;
6697 curproxy->appsession_name = strdup(args[1]);
6698 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6699 curproxy->appsession_len = atoi(args[3]);
6700 curproxy->appsession_timeout = atoi(args[5]);
6701 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6702 if (rc) {
6703 Alert("Error Init Appsession Hashtable.\n");
6704 return -1;
6705 }
6706 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006707 else if (!strcmp(args[0], "capture")) {
6708 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6709 // if (curproxy == &defproxy) {
6710 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6711 // return -1;
6712 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006713
willy tarreau4302f492005-12-18 01:00:37 +01006714 if (curproxy->capture_name != NULL) {
6715 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6716 // file, linenum, args[0]);
6717 // return 0;
6718 free(curproxy->capture_name);
6719 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006720
willy tarreau4302f492005-12-18 01:00:37 +01006721 if (*(args[4]) == 0) {
6722 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6723 file, linenum, args[0]);
6724 return -1;
6725 }
6726 curproxy->capture_name = strdup(args[2]);
6727 curproxy->capture_namelen = strlen(curproxy->capture_name);
6728 curproxy->capture_len = atol(args[4]);
6729 if (curproxy->capture_len >= CAPTURE_LEN) {
6730 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6731 file, linenum, CAPTURE_LEN - 1);
6732 curproxy->capture_len = CAPTURE_LEN - 1;
6733 }
6734 curproxy->to_log |= LW_COOKIE;
6735 }
6736 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6737 struct cap_hdr *hdr;
6738
6739 if (curproxy == &defproxy) {
6740 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6741 return -1;
6742 }
6743
6744 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6745 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6746 file, linenum, args[0], args[1]);
6747 return -1;
6748 }
6749
6750 hdr = calloc(sizeof(struct cap_hdr), 1);
6751 hdr->next = curproxy->req_cap;
6752 hdr->name = strdup(args[3]);
6753 hdr->namelen = strlen(args[3]);
6754 hdr->len = atol(args[5]);
6755 hdr->index = curproxy->nb_req_cap++;
6756 curproxy->req_cap = hdr;
6757 curproxy->to_log |= LW_REQHDR;
6758 }
6759 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6760 struct cap_hdr *hdr;
6761
6762 if (curproxy == &defproxy) {
6763 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6764 return -1;
6765 }
6766
6767 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6768 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6769 file, linenum, args[0], args[1]);
6770 return -1;
6771 }
6772 hdr = calloc(sizeof(struct cap_hdr), 1);
6773 hdr->next = curproxy->rsp_cap;
6774 hdr->name = strdup(args[3]);
6775 hdr->namelen = strlen(args[3]);
6776 hdr->len = atol(args[5]);
6777 hdr->index = curproxy->nb_rsp_cap++;
6778 curproxy->rsp_cap = hdr;
6779 curproxy->to_log |= LW_RSPHDR;
6780 }
6781 else {
6782 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006783 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006784 return -1;
6785 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006786 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006787 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006788 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006789 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006790 return 0;
6791 }
6792 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006793 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6794 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006795 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006796 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006797 curproxy->contimeout = atol(args[1]);
6798 }
6799 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006800 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006801 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6802 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006803 return 0;
6804 }
6805 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006806 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6807 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006808 return -1;
6809 }
6810 curproxy->clitimeout = atol(args[1]);
6811 }
6812 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006813 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006814 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006815 return 0;
6816 }
6817 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006818 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6819 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006820 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006821 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006822 curproxy->srvtimeout = atol(args[1]);
6823 }
6824 else if (!strcmp(args[0], "retries")) { /* connection retries */
6825 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006826 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6827 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006828 return -1;
6829 }
6830 curproxy->conn_retries = atol(args[1]);
6831 }
6832 else if (!strcmp(args[0], "option")) {
6833 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006834 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006835 return -1;
6836 }
6837 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006838 /* enable reconnections to dispatch */
6839 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006840#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006841 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006842 /* enable transparent proxy connections */
6843 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006844#endif
6845 else if (!strcmp(args[1], "keepalive"))
6846 /* enable keep-alive */
6847 curproxy->options |= PR_O_KEEPALIVE;
6848 else if (!strcmp(args[1], "forwardfor"))
6849 /* insert x-forwarded-for field */
6850 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006851 else if (!strcmp(args[1], "logasap"))
6852 /* log as soon as possible, without waiting for the session to complete */
6853 curproxy->options |= PR_O_LOGASAP;
6854 else if (!strcmp(args[1], "httpclose"))
6855 /* force connection: close in both directions in HTTP mode */
6856 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01006857 else if (!strcmp(args[1], "forceclose"))
6858 /* force connection: close in both directions in HTTP mode and enforce end of session */
6859 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006860 else if (!strcmp(args[1], "checkcache"))
6861 /* require examination of cacheability of the 'set-cookie' field */
6862 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006863 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006864 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006865 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006866 else if (!strcmp(args[1], "tcplog"))
6867 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006868 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006869 else if (!strcmp(args[1], "dontlognull")) {
6870 /* don't log empty requests */
6871 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006872 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006873 else if (!strcmp(args[1], "tcpka")) {
6874 /* enable TCP keep-alives on client and server sessions */
6875 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6876 }
6877 else if (!strcmp(args[1], "clitcpka")) {
6878 /* enable TCP keep-alives on client sessions */
6879 curproxy->options |= PR_O_TCP_CLI_KA;
6880 }
6881 else if (!strcmp(args[1], "srvtcpka")) {
6882 /* enable TCP keep-alives on server sessions */
6883 curproxy->options |= PR_O_TCP_SRV_KA;
6884 }
Willy TARREAU3481c462006-03-01 22:37:57 +01006885 else if (!strcmp(args[1], "allbackups")) {
6886 /* Use all backup servers simultaneously */
6887 curproxy->options |= PR_O_USE_ALL_BK;
6888 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006889 else if (!strcmp(args[1], "httpchk")) {
6890 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006891 if (curproxy->check_req != NULL) {
6892 free(curproxy->check_req);
6893 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006894 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006895 if (!*args[2]) { /* no argument */
6896 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6897 curproxy->check_len = strlen(DEF_CHECK_REQ);
6898 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006899 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6900 curproxy->check_req = (char *)malloc(reqlen);
6901 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6902 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006903 } else { /* more arguments : METHOD URI [HTTP_VER] */
6904 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6905 if (*args[4])
6906 reqlen += strlen(args[4]);
6907 else
6908 reqlen += strlen("HTTP/1.0");
6909
6910 curproxy->check_req = (char *)malloc(reqlen);
6911 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6912 "%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 +01006913 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006914 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006915 else if (!strcmp(args[1], "persist")) {
6916 /* persist on using the server specified by the cookie, even when it's down */
6917 curproxy->options |= PR_O_PERSIST;
6918 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006919 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006920 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006921 return -1;
6922 }
6923 return 0;
6924 }
6925 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6926 /* enable reconnections to dispatch */
6927 curproxy->options |= PR_O_REDISP;
6928 }
willy tarreaua1598082005-12-17 13:08:06 +01006929#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006930 else if (!strcmp(args[0], "transparent")) {
6931 /* enable transparent proxy connections */
6932 curproxy->options |= PR_O_TRANSP;
6933 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006934#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006935 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6936 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006937 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006938 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006939 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006940 curproxy->maxconn = atol(args[1]);
6941 }
6942 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6943 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006944 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006945 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006946 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006947 curproxy->grace = atol(args[1]);
6948 }
6949 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006950 if (curproxy == &defproxy) {
6951 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6952 return -1;
6953 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006954 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006955 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006956 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006957 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006958 curproxy->dispatch_addr = *str2sa(args[1]);
6959 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006960 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006961 if (*(args[1])) {
6962 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006963 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006964 }
willy tarreau1a3442d2006-03-24 21:03:20 +01006965 else if (!strcmp(args[1], "source")) {
6966 curproxy->options |= PR_O_BALANCE_SH;
6967 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006968 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01006969 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006970 return -1;
6971 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006972 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006973 else /* if no option is set, use round-robin by default */
6974 curproxy->options |= PR_O_BALANCE_RR;
6975 }
6976 else if (!strcmp(args[0], "server")) { /* server address */
6977 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006978 char *rport;
6979 char *raddr;
6980 short realport;
6981 int do_check;
6982
6983 if (curproxy == &defproxy) {
6984 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6985 return -1;
6986 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006987
willy tarreaua41a8b42005-12-17 14:02:24 +01006988 if (!*args[2]) {
6989 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006990 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006991 return -1;
6992 }
6993 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6994 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6995 return -1;
6996 }
willy tarreau0174f312005-12-18 01:02:42 +01006997
6998 if (curproxy->srv == NULL)
6999 curproxy->srv = newsrv;
7000 else
7001 curproxy->cursrv->next = newsrv;
7002 curproxy->cursrv = newsrv;
7003
7004 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01007005 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007006
7007 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01007008 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01007009 newsrv->id = strdup(args[1]);
7010
7011 /* several ways to check the port component :
7012 * - IP => port=+0, relative
7013 * - IP: => port=+0, relative
7014 * - IP:N => port=N, absolute
7015 * - IP:+N => port=+N, relative
7016 * - IP:-N => port=-N, relative
7017 */
7018 raddr = strdup(args[2]);
7019 rport = strchr(raddr, ':');
7020 if (rport) {
7021 *rport++ = 0;
7022 realport = atol(rport);
7023 if (!isdigit((int)*rport))
7024 newsrv->state |= SRV_MAPPORTS;
7025 } else {
7026 realport = 0;
7027 newsrv->state |= SRV_MAPPORTS;
7028 }
7029
7030 newsrv->addr = *str2sa(raddr);
7031 newsrv->addr.sin_port = htons(realport);
7032 free(raddr);
7033
willy tarreau9fe663a2005-12-17 13:02:59 +01007034 newsrv->curfd = -1; /* no health-check in progress */
7035 newsrv->inter = DEF_CHKINTR;
7036 newsrv->rise = DEF_RISETIME;
7037 newsrv->fall = DEF_FALLTIME;
7038 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7039 cur_arg = 3;
7040 while (*args[cur_arg]) {
7041 if (!strcmp(args[cur_arg], "cookie")) {
7042 newsrv->cookie = strdup(args[cur_arg + 1]);
7043 newsrv->cklen = strlen(args[cur_arg + 1]);
7044 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007045 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007046 else if (!strcmp(args[cur_arg], "rise")) {
7047 newsrv->rise = atol(args[cur_arg + 1]);
7048 newsrv->health = newsrv->rise;
7049 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007050 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007051 else if (!strcmp(args[cur_arg], "fall")) {
7052 newsrv->fall = atol(args[cur_arg + 1]);
7053 cur_arg += 2;
7054 }
7055 else if (!strcmp(args[cur_arg], "inter")) {
7056 newsrv->inter = atol(args[cur_arg + 1]);
7057 cur_arg += 2;
7058 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007059 else if (!strcmp(args[cur_arg], "port")) {
7060 newsrv->check_port = atol(args[cur_arg + 1]);
7061 cur_arg += 2;
7062 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007063 else if (!strcmp(args[cur_arg], "backup")) {
7064 newsrv->state |= SRV_BACKUP;
7065 cur_arg ++;
7066 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007067 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007068 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007069 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007070 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007071 }
willy tarreau0174f312005-12-18 01:02:42 +01007072 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7073 if (!*args[cur_arg + 1]) {
7074 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7075 file, linenum, "source");
7076 return -1;
7077 }
7078 newsrv->state |= SRV_BIND_SRC;
7079 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7080 cur_arg += 2;
7081 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007082 else {
willy tarreau0174f312005-12-18 01:02:42 +01007083 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port' and 'source'.\n",
willy tarreaua41a8b42005-12-17 14:02:24 +01007084 file, linenum, newsrv->id);
7085 return -1;
7086 }
7087 }
7088
7089 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007090 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7091 newsrv->check_port = realport; /* by default */
7092 if (!newsrv->check_port) {
7093 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 +01007094 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007095 return -1;
7096 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007097 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007098 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007099
willy tarreau62084d42006-03-24 18:57:41 +01007100 if (newsrv->state & SRV_BACKUP)
7101 curproxy->srv_bck++;
7102 else
7103 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007104 }
7105 else if (!strcmp(args[0], "log")) { /* syslog server address */
7106 struct sockaddr_in *sa;
7107 int facility;
7108
7109 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7110 curproxy->logfac1 = global.logfac1;
7111 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007112 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007113 curproxy->logfac2 = global.logfac2;
7114 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007115 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007116 }
7117 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007118 int level;
7119
willy tarreau0f7af912005-12-17 12:21:26 +01007120 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7121 if (!strcmp(log_facilities[facility], args[2]))
7122 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007123
willy tarreau0f7af912005-12-17 12:21:26 +01007124 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007125 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007126 exit(1);
7127 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007128
willy tarreau8337c6b2005-12-17 13:41:01 +01007129 level = 7; /* max syslog level = debug */
7130 if (*(args[3])) {
7131 while (level >= 0 && strcmp(log_levels[level], args[3]))
7132 level--;
7133 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007134 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007135 exit(1);
7136 }
7137 }
7138
willy tarreau0f7af912005-12-17 12:21:26 +01007139 sa = str2sa(args[1]);
7140 if (!sa->sin_port)
7141 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007142
willy tarreau0f7af912005-12-17 12:21:26 +01007143 if (curproxy->logfac1 == -1) {
7144 curproxy->logsrv1 = *sa;
7145 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007146 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007147 }
7148 else if (curproxy->logfac2 == -1) {
7149 curproxy->logsrv2 = *sa;
7150 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007151 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007152 }
7153 else {
7154 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007155 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007156 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007157 }
7158 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007159 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007160 file, linenum);
7161 return -1;
7162 }
7163 }
willy tarreaua1598082005-12-17 13:08:06 +01007164 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007165 if (!*args[1]) {
7166 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007167 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007168 return -1;
7169 }
7170
7171 curproxy->source_addr = *str2sa(args[1]);
7172 curproxy->options |= PR_O_BIND_SRC;
7173 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007174 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7175 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007176 if (curproxy == &defproxy) {
7177 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7178 return -1;
7179 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007180
7181 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007182 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7183 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007184 return -1;
7185 }
7186
7187 preg = calloc(1, sizeof(regex_t));
7188 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007189 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007190 return -1;
7191 }
7192
willy tarreauc1f47532005-12-18 01:08:26 +01007193 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7194 if (err) {
7195 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7196 file, linenum, *err);
7197 return -1;
7198 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007199 }
7200 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7201 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007202 if (curproxy == &defproxy) {
7203 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7204 return -1;
7205 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007206
7207 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007208 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007209 return -1;
7210 }
7211
7212 preg = calloc(1, sizeof(regex_t));
7213 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007214 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007215 return -1;
7216 }
7217
7218 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7219 }
7220 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7221 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007222 if (curproxy == &defproxy) {
7223 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7224 return -1;
7225 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007226
7227 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007228 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007229 return -1;
7230 }
7231
7232 preg = calloc(1, sizeof(regex_t));
7233 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007234 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007235 return -1;
7236 }
7237
7238 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7239 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007240 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7241 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007242 if (curproxy == &defproxy) {
7243 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7244 return -1;
7245 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007246
7247 if (*(args[1]) == 0) {
7248 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7249 return -1;
7250 }
7251
7252 preg = calloc(1, sizeof(regex_t));
7253 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7254 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7255 return -1;
7256 }
7257
7258 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7259 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007260 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7261 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007262 if (curproxy == &defproxy) {
7263 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7264 return -1;
7265 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007266
7267 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007268 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007269 return -1;
7270 }
7271
7272 preg = calloc(1, sizeof(regex_t));
7273 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007274 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007275 return -1;
7276 }
7277
7278 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7279 }
7280 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7281 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007282 if (curproxy == &defproxy) {
7283 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7284 return -1;
7285 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007286
7287 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007288 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7289 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007290 return -1;
7291 }
7292
7293 preg = calloc(1, sizeof(regex_t));
7294 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007295 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007296 return -1;
7297 }
7298
willy tarreauc1f47532005-12-18 01:08:26 +01007299 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7300 if (err) {
7301 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7302 file, linenum, *err);
7303 return -1;
7304 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007305 }
7306 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7307 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007308 if (curproxy == &defproxy) {
7309 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7310 return -1;
7311 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007312
7313 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007314 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007315 return -1;
7316 }
7317
7318 preg = calloc(1, sizeof(regex_t));
7319 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007320 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007321 return -1;
7322 }
7323
7324 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7325 }
7326 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7327 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007328 if (curproxy == &defproxy) {
7329 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7330 return -1;
7331 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007332
7333 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007334 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007335 return -1;
7336 }
7337
7338 preg = calloc(1, sizeof(regex_t));
7339 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007340 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007341 return -1;
7342 }
7343
7344 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7345 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007346 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7347 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007348 if (curproxy == &defproxy) {
7349 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7350 return -1;
7351 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007352
7353 if (*(args[1]) == 0) {
7354 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7355 return -1;
7356 }
7357
7358 preg = calloc(1, sizeof(regex_t));
7359 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7360 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7361 return -1;
7362 }
7363
7364 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7365 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007366 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7367 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007368 if (curproxy == &defproxy) {
7369 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7370 return -1;
7371 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007372
7373 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007374 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007375 return -1;
7376 }
7377
7378 preg = calloc(1, sizeof(regex_t));
7379 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007380 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007381 return -1;
7382 }
7383
7384 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7385 }
7386 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007387 if (curproxy == &defproxy) {
7388 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7389 return -1;
7390 }
7391
willy tarreau9fe663a2005-12-17 13:02:59 +01007392 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007393 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007394 return 0;
7395 }
7396
7397 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007398 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007399 return -1;
7400 }
7401
willy tarreau4302f492005-12-18 01:00:37 +01007402 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7403 }
7404 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7405 regex_t *preg;
7406
7407 if (*(args[1]) == 0 || *(args[2]) == 0) {
7408 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7409 file, linenum, args[0]);
7410 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007411 }
willy tarreau4302f492005-12-18 01:00:37 +01007412
7413 preg = calloc(1, sizeof(regex_t));
7414 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7415 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7416 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007417 }
willy tarreau4302f492005-12-18 01:00:37 +01007418
willy tarreauc1f47532005-12-18 01:08:26 +01007419 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7420 if (err) {
7421 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7422 file, linenum, *err);
7423 return -1;
7424 }
willy tarreau4302f492005-12-18 01:00:37 +01007425 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007426 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7427 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007428 if (curproxy == &defproxy) {
7429 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7430 return -1;
7431 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007432
7433 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007434 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007435 return -1;
7436 }
willy tarreaue39cd132005-12-17 13:00:18 +01007437
willy tarreau9fe663a2005-12-17 13:02:59 +01007438 preg = calloc(1, sizeof(regex_t));
7439 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007440 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007441 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007442 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007443
willy tarreauc1f47532005-12-18 01:08:26 +01007444 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7445 if (err) {
7446 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7447 file, linenum, *err);
7448 return -1;
7449 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007450 }
willy tarreau982249e2005-12-18 00:57:06 +01007451 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7452 regex_t *preg;
7453 if (curproxy == &defproxy) {
7454 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7455 return -1;
7456 }
7457
7458 if (*(args[1]) == 0) {
7459 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7460 return -1;
7461 }
7462
7463 preg = calloc(1, sizeof(regex_t));
7464 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7465 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7466 return -1;
7467 }
7468
willy tarreauc1f47532005-12-18 01:08:26 +01007469 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7470 if (err) {
7471 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7472 file, linenum, *err);
7473 return -1;
7474 }
willy tarreau982249e2005-12-18 00:57:06 +01007475 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007476 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007477 regex_t *preg;
7478 if (curproxy == &defproxy) {
7479 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7480 return -1;
7481 }
willy tarreaue39cd132005-12-17 13:00:18 +01007482
willy tarreaua41a8b42005-12-17 14:02:24 +01007483 if (*(args[1]) == 0 || *(args[2]) == 0) {
7484 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7485 file, linenum, args[0]);
7486 return -1;
7487 }
willy tarreaue39cd132005-12-17 13:00:18 +01007488
willy tarreaua41a8b42005-12-17 14:02:24 +01007489 preg = calloc(1, sizeof(regex_t));
7490 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7491 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7492 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007493 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007494
willy tarreauc1f47532005-12-18 01:08:26 +01007495 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7496 if (err) {
7497 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7498 file, linenum, *err);
7499 return -1;
7500 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007501 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007502 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7503 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007504 if (curproxy == &defproxy) {
7505 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7506 return -1;
7507 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007508
7509 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007510 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007511 return -1;
7512 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007513
willy tarreau9fe663a2005-12-17 13:02:59 +01007514 preg = calloc(1, sizeof(regex_t));
7515 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007516 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007517 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007518 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007519
willy tarreauc1f47532005-12-18 01:08:26 +01007520 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7521 if (err) {
7522 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7523 file, linenum, *err);
7524 return -1;
7525 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007526 }
willy tarreau982249e2005-12-18 00:57:06 +01007527 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7528 regex_t *preg;
7529 if (curproxy == &defproxy) {
7530 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7531 return -1;
7532 }
7533
7534 if (*(args[1]) == 0) {
7535 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7536 return -1;
7537 }
7538
7539 preg = calloc(1, sizeof(regex_t));
7540 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7541 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7542 return -1;
7543 }
7544
willy tarreauc1f47532005-12-18 01:08:26 +01007545 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7546 if (err) {
7547 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7548 file, linenum, *err);
7549 return -1;
7550 }
willy tarreau982249e2005-12-18 00:57:06 +01007551 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007552 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007553 if (curproxy == &defproxy) {
7554 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7555 return -1;
7556 }
7557
willy tarreau9fe663a2005-12-17 13:02:59 +01007558 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007559 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007560 return 0;
7561 }
7562
7563 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007564 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007565 return -1;
7566 }
7567
7568 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7569 }
willy tarreauc1f47532005-12-18 01:08:26 +01007570 else if (!strcmp(args[0], "errorloc") ||
7571 !strcmp(args[0], "errorloc302") ||
7572 !strcmp(args[0], "errorloc303")) { /* error location */
7573 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007574 char *err;
7575
willy tarreaueedaa9f2005-12-17 14:08:03 +01007576 // if (curproxy == &defproxy) {
7577 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7578 // return -1;
7579 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007580
willy tarreau8337c6b2005-12-17 13:41:01 +01007581 if (*(args[2]) == 0) {
7582 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7583 return -1;
7584 }
7585
7586 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007587 if (!strcmp(args[0], "errorloc303")) {
7588 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7589 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7590 } else {
7591 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7592 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7593 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007594
7595 if (errnum == 400) {
7596 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007597 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007598 free(curproxy->errmsg.msg400);
7599 }
7600 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007601 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007602 }
7603 else if (errnum == 403) {
7604 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007605 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007606 free(curproxy->errmsg.msg403);
7607 }
7608 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007609 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007610 }
7611 else if (errnum == 408) {
7612 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007613 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007614 free(curproxy->errmsg.msg408);
7615 }
7616 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007617 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007618 }
7619 else if (errnum == 500) {
7620 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007621 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007622 free(curproxy->errmsg.msg500);
7623 }
7624 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007625 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007626 }
7627 else if (errnum == 502) {
7628 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007629 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007630 free(curproxy->errmsg.msg502);
7631 }
7632 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007633 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007634 }
7635 else if (errnum == 503) {
7636 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007637 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007638 free(curproxy->errmsg.msg503);
7639 }
7640 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007641 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007642 }
7643 else if (errnum == 504) {
7644 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007645 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007646 free(curproxy->errmsg.msg504);
7647 }
7648 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007649 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007650 }
7651 else {
7652 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7653 free(err);
7654 }
7655 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007656 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007657 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007658 return -1;
7659 }
7660 return 0;
7661}
willy tarreaue39cd132005-12-17 13:00:18 +01007662
willy tarreau5cbea6f2005-12-17 12:48:26 +01007663
willy tarreau9fe663a2005-12-17 13:02:59 +01007664/*
7665 * This function reads and parses the configuration file given in the argument.
7666 * returns 0 if OK, -1 if error.
7667 */
7668int readcfgfile(char *file) {
7669 char thisline[256];
7670 char *line;
7671 FILE *f;
7672 int linenum = 0;
7673 char *end;
7674 char *args[MAX_LINE_ARGS];
7675 int arg;
7676 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007677 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007678 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007679
willy tarreau9fe663a2005-12-17 13:02:59 +01007680 struct proxy *curproxy = NULL;
7681 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007682
willy tarreau9fe663a2005-12-17 13:02:59 +01007683 if ((f=fopen(file,"r")) == NULL)
7684 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007685
willy tarreaueedaa9f2005-12-17 14:08:03 +01007686 init_default_instance();
7687
willy tarreau9fe663a2005-12-17 13:02:59 +01007688 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7689 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007690
willy tarreau9fe663a2005-12-17 13:02:59 +01007691 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007692
willy tarreau9fe663a2005-12-17 13:02:59 +01007693 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007694 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007695 line++;
7696
7697 arg = 0;
7698 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007699
willy tarreau9fe663a2005-12-17 13:02:59 +01007700 while (*line && arg < MAX_LINE_ARGS) {
7701 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7702 * C equivalent value. Other combinations left unchanged (eg: \1).
7703 */
7704 if (*line == '\\') {
7705 int skip = 0;
7706 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7707 *line = line[1];
7708 skip = 1;
7709 }
7710 else if (line[1] == 'r') {
7711 *line = '\r';
7712 skip = 1;
7713 }
7714 else if (line[1] == 'n') {
7715 *line = '\n';
7716 skip = 1;
7717 }
7718 else if (line[1] == 't') {
7719 *line = '\t';
7720 skip = 1;
7721 }
willy tarreauc1f47532005-12-18 01:08:26 +01007722 else if (line[1] == 'x') {
7723 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7724 unsigned char hex1, hex2;
7725 hex1 = toupper(line[2]) - '0';
7726 hex2 = toupper(line[3]) - '0';
7727 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7728 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7729 *line = (hex1<<4) + hex2;
7730 skip = 3;
7731 }
7732 else {
7733 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7734 return -1;
7735 }
7736 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007737 if (skip) {
7738 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7739 end -= skip;
7740 }
7741 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007742 }
willy tarreaua1598082005-12-17 13:08:06 +01007743 else if (*line == '#' || *line == '\n' || *line == '\r') {
7744 /* end of string, end of loop */
7745 *line = 0;
7746 break;
7747 }
willy tarreauc29948c2005-12-17 13:10:27 +01007748 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007749 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007750 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007751 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007752 line++;
7753 args[++arg] = line;
7754 }
7755 else {
7756 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007757 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007758 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007759
willy tarreau9fe663a2005-12-17 13:02:59 +01007760 /* empty line */
7761 if (!**args)
7762 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007763
willy tarreau9fe663a2005-12-17 13:02:59 +01007764 /* zero out remaining args */
7765 while (++arg < MAX_LINE_ARGS) {
7766 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007767 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007768
willy tarreaua41a8b42005-12-17 14:02:24 +01007769 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007770 confsect = CFG_LISTEN;
7771 else if (!strcmp(args[0], "global")) /* global config */
7772 confsect = CFG_GLOBAL;
7773 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007774
willy tarreau9fe663a2005-12-17 13:02:59 +01007775 switch (confsect) {
7776 case CFG_LISTEN:
7777 if (cfg_parse_listen(file, linenum, args) < 0)
7778 return -1;
7779 break;
7780 case CFG_GLOBAL:
7781 if (cfg_parse_global(file, linenum, args) < 0)
7782 return -1;
7783 break;
7784 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007785 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007786 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007787 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007788
7789
willy tarreau0f7af912005-12-17 12:21:26 +01007790 }
7791 fclose(f);
7792
7793 /*
7794 * Now, check for the integrity of all that we have collected.
7795 */
7796
Willy TARREAU3759f982006-03-01 22:44:17 +01007797 /* will be needed further to delay some tasks */
7798 tv_now(&now);
7799
willy tarreau0f7af912005-12-17 12:21:26 +01007800 if ((curproxy = proxy) == NULL) {
7801 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7802 file);
7803 return -1;
7804 }
7805
7806 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007807 curproxy->cursrv = NULL;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007808 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007809 curproxy = curproxy->next;
7810 continue;
7811 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007812
7813 if (curproxy->listen == NULL) {
7814 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);
7815 cfgerr++;
7816 }
7817 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007818 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007819 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007820 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7821 file, curproxy->id);
7822 cfgerr++;
7823 }
7824 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7825 if (curproxy->options & PR_O_TRANSP) {
7826 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7827 file, curproxy->id);
7828 cfgerr++;
7829 }
7830 else if (curproxy->srv == NULL) {
7831 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7832 file, curproxy->id);
7833 cfgerr++;
7834 }
willy tarreaua1598082005-12-17 13:08:06 +01007835 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007836 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7837 file, curproxy->id);
7838 }
7839 }
7840 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007841 if (curproxy->cookie_name != NULL) {
7842 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7843 file, curproxy->id);
7844 }
7845 if ((newsrv = curproxy->srv) != NULL) {
7846 Warning("parsing %s : servers will be ignored for listener %s.\n",
7847 file, curproxy->id);
7848 }
willy tarreaue39cd132005-12-17 13:00:18 +01007849 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007850 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7851 file, curproxy->id);
7852 }
willy tarreaue39cd132005-12-17 13:00:18 +01007853 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007854 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7855 file, curproxy->id);
7856 }
7857 }
7858 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7859 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7860 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7861 file, curproxy->id);
7862 cfgerr++;
7863 }
7864 else {
7865 while (newsrv != NULL) {
7866 /* nothing to check for now */
7867 newsrv = newsrv->next;
7868 }
7869 }
7870 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007871
7872 if (curproxy->options & PR_O_LOGASAP)
7873 curproxy->to_log &= ~LW_BYTES;
7874
willy tarreau8337c6b2005-12-17 13:41:01 +01007875 if (curproxy->errmsg.msg400 == NULL) {
7876 curproxy->errmsg.msg400 = (char *)HTTP_400;
7877 curproxy->errmsg.len400 = strlen(HTTP_400);
7878 }
7879 if (curproxy->errmsg.msg403 == NULL) {
7880 curproxy->errmsg.msg403 = (char *)HTTP_403;
7881 curproxy->errmsg.len403 = strlen(HTTP_403);
7882 }
7883 if (curproxy->errmsg.msg408 == NULL) {
7884 curproxy->errmsg.msg408 = (char *)HTTP_408;
7885 curproxy->errmsg.len408 = strlen(HTTP_408);
7886 }
7887 if (curproxy->errmsg.msg500 == NULL) {
7888 curproxy->errmsg.msg500 = (char *)HTTP_500;
7889 curproxy->errmsg.len500 = strlen(HTTP_500);
7890 }
7891 if (curproxy->errmsg.msg502 == NULL) {
7892 curproxy->errmsg.msg502 = (char *)HTTP_502;
7893 curproxy->errmsg.len502 = strlen(HTTP_502);
7894 }
7895 if (curproxy->errmsg.msg503 == NULL) {
7896 curproxy->errmsg.msg503 = (char *)HTTP_503;
7897 curproxy->errmsg.len503 = strlen(HTTP_503);
7898 }
7899 if (curproxy->errmsg.msg504 == NULL) {
7900 curproxy->errmsg.msg504 = (char *)HTTP_504;
7901 curproxy->errmsg.len504 = strlen(HTTP_504);
7902 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007903
7904 /* now we'll start this proxy's health checks if any */
7905 /* 1- count the checkers to run simultaneously */
7906 nbchk = 0;
7907 mininter = 0;
7908 newsrv = curproxy->srv;
7909 while (newsrv != NULL) {
7910 if (newsrv->state & SRV_CHECKED) {
7911 if (!mininter || mininter > newsrv->inter)
7912 mininter = newsrv->inter;
7913 nbchk++;
7914 }
7915 newsrv = newsrv->next;
7916 }
7917
7918 /* 2- start them as far as possible from each others while respecting
7919 * their own intervals. For this, we will start them after their own
7920 * interval added to the min interval divided by the number of servers,
7921 * weighted by the server's position in the list.
7922 */
7923 if (nbchk > 0) {
7924 struct task *t;
7925 int srvpos;
7926
7927 newsrv = curproxy->srv;
7928 srvpos = 0;
7929 while (newsrv != NULL) {
7930 /* should this server be checked ? */
7931 if (newsrv->state & SRV_CHECKED) {
7932 if ((t = pool_alloc(task)) == NULL) {
7933 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7934 return -1;
7935 }
7936
7937 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
7938 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
7939 t->state = TASK_IDLE;
7940 t->process = process_chk;
7941 t->context = newsrv;
7942
7943 /* check this every ms */
7944 tv_delayfrom(&t->expire, &now,
7945 newsrv->inter + mininter * srvpos / nbchk);
7946 task_queue(t);
7947 //task_wakeup(&rq, t);
7948 srvpos++;
7949 }
7950 newsrv = newsrv->next;
7951 }
7952 }
7953
willy tarreau0f7af912005-12-17 12:21:26 +01007954 curproxy = curproxy->next;
7955 }
7956 if (cfgerr > 0) {
7957 Alert("Errors found in configuration file, aborting.\n");
7958 return -1;
7959 }
7960 else
7961 return 0;
7962}
7963
7964
7965/*
7966 * This function initializes all the necessary variables. It only returns
7967 * if everything is OK. If something fails, it exits.
7968 */
7969void init(int argc, char **argv) {
7970 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007971 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007972 char *old_argv = *argv;
7973 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007974 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007975
7976 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007977 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007978 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007979 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007980 exit(1);
7981 }
7982
willy tarreau746e26b2006-03-25 11:14:35 +01007983#ifdef HAPROXY_MEMMAX
7984 global.rlimit_memmax = HAPROXY_MEMMAX;
7985#endif
7986
Willy TARREAUa9e75f62006-03-01 22:27:48 +01007987 /* initialize the libc's localtime structures once for all so that we
7988 * won't be missing memory if we want to send alerts under OOM conditions.
7989 */
7990 tv_now(&now);
7991 localtime(&now.tv_sec);
7992
willy tarreau4302f492005-12-18 01:00:37 +01007993 /* initialize the log header encoding map : '{|}"#' should be encoded with
7994 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7995 * URL encoding only requires '"', '#' to be encoded as well as non-
7996 * printable characters above.
7997 */
7998 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7999 memset(url_encode_map, 0, sizeof(url_encode_map));
8000 for (i = 0; i < 32; i++) {
8001 FD_SET(i, hdr_encode_map);
8002 FD_SET(i, url_encode_map);
8003 }
8004 for (i = 127; i < 256; i++) {
8005 FD_SET(i, hdr_encode_map);
8006 FD_SET(i, url_encode_map);
8007 }
8008
8009 tmp = "\"#{|}";
8010 while (*tmp) {
8011 FD_SET(*tmp, hdr_encode_map);
8012 tmp++;
8013 }
8014
8015 tmp = "\"#";
8016 while (*tmp) {
8017 FD_SET(*tmp, url_encode_map);
8018 tmp++;
8019 }
8020
willy tarreau64a3cc32005-12-18 01:13:11 +01008021 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8022#if defined(ENABLE_POLL)
8023 cfg_polling_mechanism |= POLL_USE_POLL;
8024#endif
8025#if defined(ENABLE_EPOLL)
8026 cfg_polling_mechanism |= POLL_USE_EPOLL;
8027#endif
8028
willy tarreau0f7af912005-12-17 12:21:26 +01008029 pid = getpid();
8030 progname = *argv;
8031 while ((tmp = strchr(progname, '/')) != NULL)
8032 progname = tmp + 1;
8033
8034 argc--; argv++;
8035 while (argc > 0) {
8036 char *flag;
8037
8038 if (**argv == '-') {
8039 flag = *argv+1;
8040
8041 /* 1 arg */
8042 if (*flag == 'v') {
8043 display_version();
8044 exit(0);
8045 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008046#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008047 else if (*flag == 'd' && flag[1] == 'e')
8048 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008049#endif
8050#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008051 else if (*flag == 'd' && flag[1] == 'p')
8052 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008053#endif
willy tarreau982249e2005-12-18 00:57:06 +01008054 else if (*flag == 'V')
8055 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008056 else if (*flag == 'd' && flag[1] == 'b')
8057 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008058 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008059 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008060 else if (*flag == 'c')
8061 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008062 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008063 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008064 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008065 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01008066#if STATTIME > 0
8067 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01008068 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01008069 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01008070 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01008071#endif
willy tarreau53e99702006-03-25 18:53:50 +01008072 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8073 /* list of pids to finish ('f') or terminate ('t') */
8074
8075 if (flag[1] == 'f')
8076 oldpids_sig = SIGUSR1; /* finish then exit */
8077 else
8078 oldpids_sig = SIGTERM; /* terminate immediately */
8079 argv++; argc--;
8080
8081 if (argc > 0) {
8082 oldpids = calloc(argc, sizeof(int));
8083 while (argc > 0) {
8084 oldpids[nb_oldpids] = atol(*argv);
8085 if (oldpids[nb_oldpids] <= 0)
8086 usage(old_argv);
8087 argc--; argv++;
8088 nb_oldpids++;
8089 }
8090 }
8091 }
willy tarreau0f7af912005-12-17 12:21:26 +01008092 else { /* >=2 args */
8093 argv++; argc--;
8094 if (argc == 0)
8095 usage(old_argv);
8096
8097 switch (*flag) {
8098 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008099 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008100 case 'N' : cfg_maxpconn = atol(*argv); break;
8101 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008102 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008103 default: usage(old_argv);
8104 }
8105 }
8106 }
8107 else
8108 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008109 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008110 }
8111
willy tarreaud0fb4652005-12-18 01:32:04 +01008112 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008113 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8114 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008115
willy tarreau0f7af912005-12-17 12:21:26 +01008116 if (!cfg_cfgfile)
8117 usage(old_argv);
8118
8119 gethostname(hostname, MAX_HOSTNAME_LEN);
8120
willy tarreau12350152005-12-18 01:03:27 +01008121 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008122 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008123 if (readcfgfile(cfg_cfgfile) < 0) {
8124 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8125 exit(1);
8126 }
willy tarreau12350152005-12-18 01:03:27 +01008127 if (have_appsession)
8128 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008129
willy tarreau982249e2005-12-18 00:57:06 +01008130 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008131 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8132 exit(0);
8133 }
8134
willy tarreau9fe663a2005-12-17 13:02:59 +01008135 if (cfg_maxconn > 0)
8136 global.maxconn = cfg_maxconn;
8137
willy tarreaufe2c5c12005-12-17 14:14:34 +01008138 if (cfg_pidfile) {
8139 if (global.pidfile)
8140 free(global.pidfile);
8141 global.pidfile = strdup(cfg_pidfile);
8142 }
8143
willy tarreau9fe663a2005-12-17 13:02:59 +01008144 if (global.maxconn == 0)
8145 global.maxconn = DEFAULT_MAXCONN;
8146
Willy TARREAU203b0b62006-03-12 18:00:28 +01008147 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008148
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008149 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008150 /* command line debug mode inhibits configuration mode */
8151 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8152 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008153 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8154 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008155
8156 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8157 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8158 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8159 }
8160
8161 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008162 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8163 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008164 global.nbproc = 1;
8165 }
8166
8167 if (global.nbproc < 1)
8168 global.nbproc = 1;
8169
willy tarreau0f7af912005-12-17 12:21:26 +01008170 StaticReadEvent = (fd_set *)calloc(1,
8171 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008172 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008173 StaticWriteEvent = (fd_set *)calloc(1,
8174 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008175 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008176
8177 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008178 sizeof(struct fdtab) * (global.maxsock));
8179 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008180 fdtab[i].state = FD_STCLOSE;
8181 }
8182}
8183
8184/*
willy tarreau41310e72006-03-25 18:17:56 +01008185 * this function starts all the proxies. Its return value is composed from
8186 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8187 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008188 */
willy tarreau41310e72006-03-25 18:17:56 +01008189int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008190 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008191 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008192 int err = ERR_NONE;
8193 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008194
8195 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008196 if (curproxy->state != PR_STNEW)
8197 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01008198
willy tarreau41310e72006-03-25 18:17:56 +01008199 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01008200 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008201 if (listener->fd != -1)
8202 continue; /* already initialized */
8203
8204 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
8205 if (verbose)
8206 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8207 curproxy->id);
8208 err |= ERR_RETRYABLE;
8209 pxerr |= 1;
8210 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008211 }
willy tarreau0f7af912005-12-17 12:21:26 +01008212
willy tarreaua41a8b42005-12-17 14:02:24 +01008213 if (fd >= global.maxsock) {
8214 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
8215 curproxy->id);
8216 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008217 err |= ERR_FATAL;
8218 pxerr |= 1;
8219 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008220 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008221
willy tarreaua41a8b42005-12-17 14:02:24 +01008222 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
8223 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
8224 (char *) &one, sizeof(one)) == -1)) {
8225 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
8226 curproxy->id);
8227 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008228 err |= ERR_FATAL;
8229 pxerr |= 1;
8230 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008231 }
willy tarreau0f7af912005-12-17 12:21:26 +01008232
willy tarreaua41a8b42005-12-17 14:02:24 +01008233 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8234 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8235 curproxy->id);
8236 }
willy tarreau0f7af912005-12-17 12:21:26 +01008237
willy tarreaua41a8b42005-12-17 14:02:24 +01008238 if (bind(fd,
8239 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008240 listener->addr.ss_family == AF_INET6 ?
8241 sizeof(struct sockaddr_in6) :
8242 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008243 if (verbose)
8244 Alert("cannot bind socket for proxy %s. Aborting.\n",
8245 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008246 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008247 err |= ERR_RETRYABLE;
8248 pxerr |= 1;
8249 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008250 }
willy tarreau0f7af912005-12-17 12:21:26 +01008251
willy tarreaua41a8b42005-12-17 14:02:24 +01008252 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008253 if (verbose)
8254 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8255 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008256 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008257 err |= ERR_RETRYABLE;
8258 pxerr |= 1;
8259 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008260 }
willy tarreau0f7af912005-12-17 12:21:26 +01008261
willy tarreau41310e72006-03-25 18:17:56 +01008262 /* the socket is ready */
8263 listener->fd = fd;
8264
willy tarreaua41a8b42005-12-17 14:02:24 +01008265 /* the function for the accept() event */
8266 fdtab[fd].read = &event_accept;
8267 fdtab[fd].write = NULL; /* never called */
8268 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01008269 fdtab[fd].state = FD_STLISTEN;
8270 FD_SET(fd, StaticReadEvent);
8271 fd_insert(fd);
8272 listeners++;
8273 }
willy tarreau41310e72006-03-25 18:17:56 +01008274
8275 if (!pxerr) {
8276 curproxy->state = PR_STRUN;
8277 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
8278 }
willy tarreau0f7af912005-12-17 12:21:26 +01008279 }
willy tarreau41310e72006-03-25 18:17:56 +01008280
8281 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01008282}
8283
willy tarreaub952e1d2005-12-18 01:31:20 +01008284int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008285
8286 appsess *temp1,*temp2;
8287 temp1 = (appsess *)key1;
8288 temp2 = (appsess *)key2;
8289
8290 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8291 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8292
8293 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8294}/* end match_str */
8295
willy tarreaub952e1d2005-12-18 01:31:20 +01008296void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008297 appsess *temp1;
8298
8299 //printf("destroy called\n");
8300 temp1 = (appsess *)data;
8301
8302 if (temp1->sessid)
8303 pool_free_to(apools.sessid, temp1->sessid);
8304
8305 if (temp1->serverid)
8306 pool_free_to(apools.serverid, temp1->serverid);
8307
8308 pool_free(appsess, temp1);
8309} /* end destroy */
8310
8311void appsession_cleanup( void )
8312{
8313 struct proxy *p = proxy;
8314
8315 while(p) {
8316 chtbl_destroy(&(p->htbl_proxy));
8317 p = p->next;
8318 }
8319}/* end appsession_cleanup() */
8320
8321void pool_destroy(void **pool)
8322{
8323 void *temp, *next;
8324 next = pool;
8325 while (next) {
8326 temp = next;
8327 next = *(void **)temp;
8328 free(temp);
8329 }
8330}/* end pool_destroy() */
8331
willy tarreaub952e1d2005-12-18 01:31:20 +01008332void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008333 struct proxy *p = proxy;
8334 struct cap_hdr *h,*h_next;
8335 struct server *s,*s_next;
8336 struct listener *l,*l_next;
8337
8338 while (p) {
8339 if (p->id)
8340 free(p->id);
8341
8342 if (p->check_req)
8343 free(p->check_req);
8344
8345 if (p->cookie_name)
8346 free(p->cookie_name);
8347
8348 if (p->capture_name)
8349 free(p->capture_name);
8350
8351 /* only strup if the user have set in config.
8352 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008353 if (p->errmsg.msg400) free(p->errmsg.msg400);
8354 if (p->errmsg.msg403) free(p->errmsg.msg403);
8355 if (p->errmsg.msg408) free(p->errmsg.msg408);
8356 if (p->errmsg.msg500) free(p->errmsg.msg500);
8357 if (p->errmsg.msg502) free(p->errmsg.msg502);
8358 if (p->errmsg.msg503) free(p->errmsg.msg503);
8359 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008360 */
8361 if (p->appsession_name)
8362 free(p->appsession_name);
8363
8364 h = p->req_cap;
8365 while (h) {
8366 h_next = h->next;
8367 if (h->name)
8368 free(h->name);
8369 pool_destroy(h->pool);
8370 free(h);
8371 h = h_next;
8372 }/* end while(h) */
8373
8374 h = p->rsp_cap;
8375 while (h) {
8376 h_next = h->next;
8377 if (h->name)
8378 free(h->name);
8379
8380 pool_destroy(h->pool);
8381 free(h);
8382 h = h_next;
8383 }/* end while(h) */
8384
8385 s = p->srv;
8386 while (s) {
8387 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008388 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008389 free(s->id);
8390
willy tarreaub952e1d2005-12-18 01:31:20 +01008391 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008392 free(s->cookie);
8393
8394 free(s);
8395 s = s_next;
8396 }/* end while(s) */
8397
8398 l = p->listen;
8399 while (l) {
8400 l_next = l->next;
8401 free(l);
8402 l = l_next;
8403 }/* end while(l) */
8404
8405 pool_destroy((void **) p->req_cap_pool);
8406 pool_destroy((void **) p->rsp_cap_pool);
8407 p = p->next;
8408 }/* end while(p) */
8409
8410 if (global.chroot) free(global.chroot);
8411 if (global.pidfile) free(global.pidfile);
8412
willy tarreau12350152005-12-18 01:03:27 +01008413 if (StaticReadEvent) free(StaticReadEvent);
8414 if (StaticWriteEvent) free(StaticWriteEvent);
8415 if (fdtab) free(fdtab);
8416
8417 pool_destroy(pool_session);
8418 pool_destroy(pool_buffer);
8419 pool_destroy(pool_fdtab);
8420 pool_destroy(pool_requri);
8421 pool_destroy(pool_task);
8422 pool_destroy(pool_capture);
8423 pool_destroy(pool_appsess);
8424
8425 if (have_appsession) {
8426 pool_destroy(apools.serverid);
8427 pool_destroy(apools.sessid);
8428 }
8429} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008430
willy tarreau41310e72006-03-25 18:17:56 +01008431/* sends the signal <sig> to all pids found in <oldpids> */
8432static void tell_old_pids(int sig) {
8433 int p;
8434 for (p = 0; p < nb_oldpids; p++)
8435 kill(oldpids[p], sig);
8436}
8437
willy tarreau0f7af912005-12-17 12:21:26 +01008438int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01008439 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01008440 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008441 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008442 init(argc, argv);
8443
willy tarreau0f7af912005-12-17 12:21:26 +01008444 signal(SIGQUIT, dump);
8445 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008446 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008447#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008448 signal(SIGINT, sig_int);
8449 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008450#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008451
8452 /* on very high loads, a sigpipe sometimes happen just between the
8453 * getsockopt() which tells "it's OK to write", and the following write :-(
8454 */
willy tarreau3242e862005-12-17 12:27:53 +01008455#ifndef MSG_NOSIGNAL
8456 signal(SIGPIPE, SIG_IGN);
8457#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008458
willy tarreau41310e72006-03-25 18:17:56 +01008459 /* We will loop at most 100 times with 10 ms delay each time.
8460 * That's at most 1 second. We only send a signal to old pids
8461 * if we cannot grab at least one port.
8462 */
8463 retry = MAX_START_RETRIES;
8464 err = ERR_NONE;
8465 while (retry >= 0) {
8466 struct timeval w;
8467 err = start_proxies(retry == 0 || nb_oldpids == 0);
8468 if (err != ERR_RETRYABLE)
8469 break;
8470 if (nb_oldpids == 0)
8471 break;
8472
8473 tell_old_pids(SIGTTOU);
8474 /* give some time to old processes to stop listening */
8475 w.tv_sec = 0;
8476 w.tv_usec = 10*1000;
8477 select(0, NULL, NULL, NULL, &w);
8478 retry--;
8479 }
8480
8481 /* Note: start_proxies() sends an alert when it fails. */
8482 if (err != ERR_NONE) {
8483 if (retry != MAX_START_RETRIES && nb_oldpids)
8484 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01008485 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01008486 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008487
8488 if (listeners == 0) {
8489 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008490 /* Note: we don't have to send anything to the old pids because we
8491 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01008492 exit(1);
8493 }
8494
willy tarreaudbd3bef2006-01-20 19:35:18 +01008495 /* prepare pause/play signals */
8496 signal(SIGTTOU, sig_pause);
8497 signal(SIGTTIN, sig_listen);
8498
Willy TARREAUe3283d12006-03-01 22:15:29 +01008499 if (global.mode & MODE_DAEMON) {
8500 global.mode &= ~MODE_VERBOSE;
8501 global.mode |= MODE_QUIET;
8502 }
8503
willy tarreaud0fb4652005-12-18 01:32:04 +01008504 /* MODE_QUIET can inhibit alerts and warnings below this line */
8505
8506 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008507 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008508 /* detach from the tty */
8509 fclose(stdin); fclose(stdout); fclose(stderr);
8510 close(0); close(1); close(2);
8511 }
willy tarreau0f7af912005-12-17 12:21:26 +01008512
willy tarreaufe2c5c12005-12-17 14:14:34 +01008513 /* open log & pid files before the chroot */
8514 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8515 int pidfd;
8516 unlink(global.pidfile);
8517 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8518 if (pidfd < 0) {
8519 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01008520 if (nb_oldpids)
8521 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01008522 exit(1);
8523 }
8524 pidfile = fdopen(pidfd, "w");
8525 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008526
8527 /* chroot if needed */
8528 if (global.chroot != NULL) {
8529 if (chroot(global.chroot) == -1) {
8530 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01008531 if (nb_oldpids)
8532 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01008533 }
8534 chdir("/");
8535 }
8536
willy tarreaub1285d52005-12-18 01:20:14 +01008537 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01008538 if (!global.rlimit_nofile)
8539 global.rlimit_nofile = global.maxsock;
8540
willy tarreaub1285d52005-12-18 01:20:14 +01008541 if (global.rlimit_nofile) {
8542 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8543 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8544 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8545 }
willy tarreau746e26b2006-03-25 11:14:35 +01008546 }
8547
8548 if (global.rlimit_memmax) {
8549 limit.rlim_cur = limit.rlim_max =
8550 global.rlimit_memmax * 1048576 / global.nbproc;
8551#ifdef RLIMIT_AS
8552 if (setrlimit(RLIMIT_AS, &limit) == -1) {
8553 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8554 argv[0], global.rlimit_memmax);
8555 }
8556#else
8557 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
8558 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8559 argv[0], global.rlimit_memmax);
8560 }
8561#endif
willy tarreaub1285d52005-12-18 01:20:14 +01008562 }
8563
willy tarreau41310e72006-03-25 18:17:56 +01008564 if (nb_oldpids)
8565 tell_old_pids(oldpids_sig);
8566
8567 /* Note that any error at this stage will be fatal because we will not
8568 * be able to restart the old pids.
8569 */
8570
willy tarreau9fe663a2005-12-17 13:02:59 +01008571 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008572 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008573 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8574 exit(1);
8575 }
8576
willy tarreau036e1ce2005-12-17 13:46:33 +01008577 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008578 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8579 exit(1);
8580 }
8581
willy tarreaub1285d52005-12-18 01:20:14 +01008582 /* check ulimits */
8583 limit.rlim_cur = limit.rlim_max = 0;
8584 getrlimit(RLIMIT_NOFILE, &limit);
8585 if (limit.rlim_cur < global.maxsock) {
8586 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",
8587 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8588 }
8589
willy tarreau9fe663a2005-12-17 13:02:59 +01008590 if (global.mode & MODE_DAEMON) {
8591 int ret = 0;
8592 int proc;
8593
8594 /* the father launches the required number of processes */
8595 for (proc = 0; proc < global.nbproc; proc++) {
8596 ret = fork();
8597 if (ret < 0) {
8598 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008599 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01008600 exit(1); /* there has been an error */
8601 }
8602 else if (ret == 0) /* child breaks here */
8603 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008604 if (pidfile != NULL) {
8605 fprintf(pidfile, "%d\n", ret);
8606 fflush(pidfile);
8607 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008608 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008609 /* close the pidfile both in children and father */
8610 if (pidfile != NULL)
8611 fclose(pidfile);
8612 free(global.pidfile);
8613
willy tarreau9fe663a2005-12-17 13:02:59 +01008614 if (proc == global.nbproc)
8615 exit(0); /* parent must leave */
8616
willy tarreau750a4722005-12-17 13:21:24 +01008617 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8618 * that we can detach from the TTY. We MUST NOT do it in other cases since
8619 * it would have already be done, and 0-2 would have been affected to listening
8620 * sockets
8621 */
8622 if (!(global.mode & MODE_QUIET)) {
8623 /* detach from the tty */
8624 fclose(stdin); fclose(stdout); fclose(stderr);
8625 close(0); close(1); close(2); /* close all fd's */
8626 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8627 }
willy tarreaua1598082005-12-17 13:08:06 +01008628 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008629 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008630 }
8631
willy tarreau1c2ad212005-12-18 01:11:29 +01008632#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008633 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008634 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8635 epoll_loop(POLL_LOOP_ACTION_RUN);
8636 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008637 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008638 }
8639 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008640 Warning("epoll() is not available. Using poll()/select() instead.\n");
8641 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008642 }
8643 }
8644#endif
8645
8646#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008647 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008648 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8649 poll_loop(POLL_LOOP_ACTION_RUN);
8650 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008651 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008652 }
8653 else {
8654 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008655 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008656 }
8657 }
8658#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008659 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008660 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8661 select_loop(POLL_LOOP_ACTION_RUN);
8662 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008663 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008664 }
8665 }
8666
willy tarreau0f7af912005-12-17 12:21:26 +01008667
willy tarreau12350152005-12-18 01:03:27 +01008668 /* Free all Hash Keys and all Hash elements */
8669 appsession_cleanup();
8670 /* Do some cleanup */
8671 deinit();
8672
willy tarreau0f7af912005-12-17 12:21:26 +01008673 exit(0);
8674}
willy tarreau12350152005-12-18 01:03:27 +01008675
8676#if defined(DEBUG_HASH)
8677static void print_table(const CHTbl *htbl) {
8678
8679 ListElmt *element;
8680 int i;
8681 appsess *asession;
8682
8683 /*****************************************************************************
8684 * *
8685 * Display the chained hash table. *
8686 * *
8687 *****************************************************************************/
8688
8689 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8690
8691 for (i = 0; i < TBLSIZ; i++) {
8692 fprintf(stdout, "Bucket[%03d]\n", i);
8693
8694 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8695 //fprintf(stdout, "%c", *(char *)list_data(element));
8696 asession = (appsess *)list_data(element);
8697 fprintf(stdout, "ELEM :%s:", asession->sessid);
8698 fprintf(stdout, " Server :%s: \n", asession->serverid);
8699 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8700 }
8701
8702 fprintf(stdout, "\n");
8703 }
8704 return;
8705} /* end print_table */
8706#endif
8707
8708static int appsession_init(void)
8709{
8710 static int initialized = 0;
8711 int idlen;
8712 struct server *s;
8713 struct proxy *p = proxy;
8714
8715 if (!initialized) {
8716 if (!appsession_task_init()) {
8717 apools.sessid = NULL;
8718 apools.serverid = NULL;
8719 apools.ser_waste = 0;
8720 apools.ser_use = 0;
8721 apools.ser_msize = sizeof(void *);
8722 apools.ses_waste = 0;
8723 apools.ses_use = 0;
8724 apools.ses_msize = sizeof(void *);
8725 while (p) {
8726 s = p->srv;
8727 if (apools.ses_msize < p->appsession_len)
8728 apools.ses_msize = p->appsession_len;
8729 while (s) {
8730 idlen = strlen(s->id);
8731 if (apools.ser_msize < idlen)
8732 apools.ser_msize = idlen;
8733 s = s->next;
8734 }
8735 p = p->next;
8736 }
8737 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8738 apools.ses_msize ++;
8739 }
8740 else {
8741 fprintf(stderr, "appsession_task_init failed\n");
8742 return -1;
8743 }
8744 initialized ++;
8745 }
8746 return 0;
8747}
8748
8749static int appsession_task_init(void)
8750{
8751 static int initialized = 0;
8752 struct task *t;
8753 if (!initialized) {
8754 if ((t = pool_alloc(task)) == NULL)
8755 return -1;
8756 t->next = t->prev = t->rqnext = NULL;
8757 t->wq = LIST_HEAD(wait_queue);
8758 t->state = TASK_IDLE;
8759 t->context = NULL;
8760 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8761 task_queue(t);
8762 t->process = appsession_refresh;
8763 initialized ++;
8764 }
8765 return 0;
8766}
8767
8768static int appsession_refresh(struct task *t) {
8769 struct proxy *p = proxy;
8770 CHTbl *htbl;
8771 ListElmt *element, *last;
8772 int i;
8773 appsess *asession;
8774 void *data;
8775
8776 while (p) {
8777 if (p->appsession_name != NULL) {
8778 htbl = &p->htbl_proxy;
8779 /* if we ever give up the use of TBLSIZ, we need to change this */
8780 for (i = 0; i < TBLSIZ; i++) {
8781 last = NULL;
8782 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8783 asession = (appsess *)list_data(element);
8784 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8785 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8786 int len;
8787 /*
8788 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8789 */
8790 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8791 asession->sessid, asession->serverid?asession->serverid:"(null)");
8792 write(1, trash, len);
8793 }
8794 /* delete the expired element from within the hash table */
8795 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8796 && (htbl->table[i].destroy != NULL)) {
8797 htbl->table[i].destroy(data);
8798 }
8799 if (last == NULL) {/* patient lost his head, get a new one */
8800 element = list_head(&htbl->table[i]);
8801 if (element == NULL) break; /* no heads left, go to next patient */
8802 }
8803 else
8804 element = last;
8805 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8806 else
8807 last = element;
8808 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8809 }
8810 }
8811 p = p->next;
8812 }
8813 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8814 return TBLCHKINT;
8815} /* end appsession_refresh */
8816