blob: d6c757ee190d23595e019a0df296ec3b9cd19aa9 [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 tarreau704f32b2006-04-07 17:37:55 +02004282 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01004283 return 1;
4284 }
4285 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004286 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004287
willy tarreau0f7af912005-12-17 12:21:26 +01004288 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004289 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004290 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004291 tv_eternity(&t->swexpire);
4292 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004293 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004294 if (t->proxy->srvtimeout) {
4295 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4296 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4297 t->srexpire = t->swexpire;
4298 }
4299 else
4300 tv_eternity(&t->swexpire);
4301 }
willy tarreau0f7af912005-12-17 12:21:26 +01004302
4303 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4304 FD_SET(t->srv_fd, StaticReadEvent);
4305 if (t->proxy->srvtimeout)
4306 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4307 else
4308 tv_eternity(&t->srexpire);
4309
4310 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004311 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004312
4313 /* if the user wants to log as soon as possible, without counting
4314 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004315 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004316 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4317 sess_log(t);
4318 }
willy tarreau0f7af912005-12-17 12:21:26 +01004319 }
willy tarreauef900ab2005-12-17 12:52:52 +01004320 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004321 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004322 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4323 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004324 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004325 return 1;
4326 }
4327 }
4328 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004329 /* now parse the partial (or complete) headers */
4330 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4331 char *ptr;
4332 int delete_header;
4333
4334 ptr = rep->lr;
4335
4336 /* look for the end of the current header */
4337 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4338 ptr++;
4339
4340 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004341 int line, len;
4342
4343 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004344
4345 /* first, we'll block if security checks have caught nasty things */
4346 if (t->flags & SN_CACHEABLE) {
4347 if ((t->flags & SN_CACHE_COOK) &&
4348 (t->flags & SN_SCK_ANY) &&
4349 (t->proxy->options & PR_O_CHK_CACHE)) {
4350
4351 /* we're in presence of a cacheable response containing
4352 * a set-cookie header. We'll block it as requested by
4353 * the 'checkcache' option, and send an alert.
4354 */
4355 tv_eternity(&t->srexpire);
4356 tv_eternity(&t->swexpire);
4357 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004358 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01004359 t->srv_state = SV_STCLOSE;
4360 t->logs.status = 502;
4361 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4362 if (!(t->flags & SN_ERR_MASK))
4363 t->flags |= SN_ERR_PRXCOND;
4364 if (!(t->flags & SN_FINST_MASK))
4365 t->flags |= SN_FINST_H;
4366
4367 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4368 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4369
willy tarreau704f32b2006-04-07 17:37:55 +02004370 /* TODO : check if there are pending connections on this server */
willy tarreau97f58572005-12-18 00:53:44 +01004371 return 1;
4372 }
4373 }
4374
willy tarreau982249e2005-12-18 00:57:06 +01004375 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4376 if (t->flags & SN_SVDENY) {
4377 tv_eternity(&t->srexpire);
4378 tv_eternity(&t->swexpire);
4379 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004380 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01004381 t->srv_state = SV_STCLOSE;
4382 t->logs.status = 502;
4383 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4384 if (!(t->flags & SN_ERR_MASK))
4385 t->flags |= SN_ERR_PRXCOND;
4386 if (!(t->flags & SN_FINST_MASK))
4387 t->flags |= SN_FINST_H;
willy tarreau704f32b2006-04-07 17:37:55 +02004388 /* TODO : check if there are pending connections on this server */
willy tarreau982249e2005-12-18 00:57:06 +01004389 return 1;
4390 }
4391
willy tarreau5cbea6f2005-12-17 12:48:26 +01004392 /* we'll have something else to do here : add new headers ... */
4393
willy tarreaucd878942005-12-17 13:27:43 +01004394 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4395 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004396 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004397 * insert a set-cookie here, except if we want to insert only on POST
4398 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004399 */
willy tarreau750a4722005-12-17 13:21:24 +01004400 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004401 t->proxy->cookie_name,
4402 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004403
willy tarreau036e1ce2005-12-17 13:46:33 +01004404 t->flags |= SN_SCK_INSERTED;
4405
willy tarreau750a4722005-12-17 13:21:24 +01004406 /* Here, we will tell an eventual cache on the client side that we don't
4407 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4408 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4409 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4410 */
willy tarreau240afa62005-12-17 13:14:35 +01004411 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004412 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4413 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004414
4415 if (rep->data + rep->l < rep->h)
4416 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4417 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004418 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004419 }
4420
4421 /* headers to be added */
4422 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004423 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4424 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004425 }
4426
willy tarreau25c4ea52005-12-18 00:49:49 +01004427 /* add a "connection: close" line if needed */
4428 if (t->proxy->options & PR_O_HTTP_CLOSE)
4429 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4430
willy tarreau5cbea6f2005-12-17 12:48:26 +01004431 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004432 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004433 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004434
Willy TARREAU767ba712006-03-01 22:40:50 +01004435 /* client connection already closed or option 'httpclose' required :
4436 * we close the server's outgoing connection right now.
4437 */
4438 if ((req->l == 0) &&
4439 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4440 FD_CLR(t->srv_fd, StaticWriteEvent);
4441 tv_eternity(&t->swexpire);
4442
4443 /* We must ensure that the read part is still alive when switching
4444 * to shutw */
4445 FD_SET(t->srv_fd, StaticReadEvent);
4446 if (t->proxy->srvtimeout)
4447 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4448
4449 shutdown(t->srv_fd, SHUT_WR);
4450 t->srv_state = SV_STSHUTW;
4451 }
4452
willy tarreau25c4ea52005-12-18 00:49:49 +01004453 /* if the user wants to log as soon as possible, without counting
4454 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004455 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004456 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4457 t->logs.bytes = rep->h - rep->data;
4458 sess_log(t);
4459 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004460 break;
4461 }
4462
4463 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4464 if (ptr > rep->r - 2) {
4465 /* this is a partial header, let's wait for more to come */
4466 rep->lr = ptr;
4467 break;
4468 }
4469
4470 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4471 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4472
4473 /* now we know that *ptr is either \r or \n,
4474 * and that there are at least 1 char after it.
4475 */
4476 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4477 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4478 else
4479 rep->lr = ptr + 2; /* \r\n or \n\r */
4480
4481 /*
4482 * now we know that we have a full header ; we can do whatever
4483 * we want with these pointers :
4484 * rep->h = beginning of header
4485 * ptr = end of header (first \r or \n)
4486 * rep->lr = beginning of next line (next rep->h)
4487 * rep->r = end of data (not used at this stage)
4488 */
4489
willy tarreaua1598082005-12-17 13:08:06 +01004490
willy tarreau982249e2005-12-18 00:57:06 +01004491 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004492 t->logs.logwait &= ~LW_RESP;
4493 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004494 switch (t->logs.status) {
4495 case 200:
4496 case 203:
4497 case 206:
4498 case 300:
4499 case 301:
4500 case 410:
4501 /* RFC2616 @13.4:
4502 * "A response received with a status code of
4503 * 200, 203, 206, 300, 301 or 410 MAY be stored
4504 * by a cache (...) unless a cache-control
4505 * directive prohibits caching."
4506 *
4507 * RFC2616 @9.5: POST method :
4508 * "Responses to this method are not cacheable,
4509 * unless the response includes appropriate
4510 * Cache-Control or Expires header fields."
4511 */
4512 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4513 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4514 break;
4515 default:
4516 break;
4517 }
willy tarreau4302f492005-12-18 01:00:37 +01004518 }
4519 else if (t->logs.logwait & LW_RSPHDR) {
4520 struct cap_hdr *h;
4521 int len;
4522 for (h = t->proxy->rsp_cap; h; h = h->next) {
4523 if ((h->namelen + 2 <= ptr - rep->h) &&
4524 (rep->h[h->namelen] == ':') &&
4525 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4526
4527 if (t->rsp_cap[h->index] == NULL)
4528 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4529
4530 len = ptr - (rep->h + h->namelen + 2);
4531 if (len > h->len)
4532 len = h->len;
4533
4534 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4535 t->rsp_cap[h->index][len]=0;
4536 }
4537 }
4538
willy tarreaua1598082005-12-17 13:08:06 +01004539 }
4540
willy tarreau5cbea6f2005-12-17 12:48:26 +01004541 delete_header = 0;
4542
willy tarreau982249e2005-12-18 00:57:06 +01004543 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004544 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004545 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 +01004546 max = ptr - rep->h;
4547 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004548 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004549 trash[len++] = '\n';
4550 write(1, trash, len);
4551 }
4552
willy tarreau25c4ea52005-12-18 00:49:49 +01004553 /* remove "connection: " if needed */
4554 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4555 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4556 delete_header = 1;
4557 }
4558
willy tarreau5cbea6f2005-12-17 12:48:26 +01004559 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004560 if (!delete_header && t->proxy->rsp_exp != NULL
4561 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004562 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004563 char term;
4564
4565 term = *ptr;
4566 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004567 exp = t->proxy->rsp_exp;
4568 do {
4569 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4570 switch (exp->action) {
4571 case ACT_ALLOW:
4572 if (!(t->flags & SN_SVDENY))
4573 t->flags |= SN_SVALLOW;
4574 break;
4575 case ACT_REPLACE:
4576 if (!(t->flags & SN_SVDENY)) {
4577 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4578 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4579 }
4580 break;
4581 case ACT_REMOVE:
4582 if (!(t->flags & SN_SVDENY))
4583 delete_header = 1;
4584 break;
4585 case ACT_DENY:
4586 if (!(t->flags & SN_SVALLOW))
4587 t->flags |= SN_SVDENY;
4588 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004589 case ACT_PASS: /* we simply don't deny this one */
4590 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004591 }
4592 break;
4593 }
willy tarreaue39cd132005-12-17 13:00:18 +01004594 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004595 *ptr = term; /* restore the string terminator */
4596 }
4597
willy tarreau97f58572005-12-18 00:53:44 +01004598 /* check for cache-control: or pragma: headers */
4599 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4600 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4601 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4602 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4603 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004604 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004605 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4606 else {
4607 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004608 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004609 t->flags &= ~SN_CACHE_COOK;
4610 }
4611 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004612 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004613 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004614 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004615 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4616 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004617 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004618 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004619 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4620 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4621 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4622 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4623 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4624 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004625 }
4626 }
4627 }
4628
willy tarreau5cbea6f2005-12-17 12:48:26 +01004629 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004630 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004631 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004632 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004633 char *p1, *p2, *p3, *p4;
4634
willy tarreau97f58572005-12-18 00:53:44 +01004635 t->flags |= SN_SCK_ANY;
4636
willy tarreau5cbea6f2005-12-17 12:48:26 +01004637 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4638
4639 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004640 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004641 p1++;
4642
4643 if (p1 == ptr || *p1 == ';') /* end of cookie */
4644 break;
4645
4646 /* p1 is at the beginning of the cookie name */
4647 p2 = p1;
4648
4649 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4650 p2++;
4651
4652 if (p2 == ptr || *p2 == ';') /* next cookie */
4653 break;
4654
4655 p3 = p2 + 1; /* skips the '=' sign */
4656 if (p3 == ptr)
4657 break;
4658
4659 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004660 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004661 p4++;
4662
4663 /* here, we have the cookie name between p1 and p2,
4664 * and its value between p3 and p4.
4665 * we can process it.
4666 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004667
4668 /* first, let's see if we want to capture it */
4669 if (t->proxy->capture_name != NULL &&
4670 t->logs.srv_cookie == NULL &&
4671 (p4 - p1 >= t->proxy->capture_namelen) &&
4672 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4673 int log_len = p4 - p1;
4674
4675 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4676 Alert("HTTP logging : out of memory.\n");
4677 }
4678
4679 if (log_len > t->proxy->capture_len)
4680 log_len = t->proxy->capture_len;
4681 memcpy(t->logs.srv_cookie, p1, log_len);
4682 t->logs.srv_cookie[log_len] = 0;
4683 }
4684
4685 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4686 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004687 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004688 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004689
4690 /* If the cookie is in insert mode on a known server, we'll delete
4691 * this occurrence because we'll insert another one later.
4692 * We'll delete it too if the "indirect" option is set and we're in
4693 * a direct access. */
4694 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004695 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004696 /* this header must be deleted */
4697 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004698 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004699 }
4700 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4701 /* replace bytes p3->p4 with the cookie name associated
4702 * with this server since we know it.
4703 */
4704 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004705 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004706 }
willy tarreau0174f312005-12-18 01:02:42 +01004707 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4708 /* insert the cookie name associated with this server
4709 * before existing cookie, and insert a delimitor between them..
4710 */
4711 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4712 p3[t->srv->cklen] = COOKIE_DELIM;
4713 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4714 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004715 break;
4716 }
willy tarreau12350152005-12-18 01:03:27 +01004717
4718 /* first, let's see if the cookie is our appcookie*/
4719 if ((t->proxy->appsession_name != NULL) &&
4720 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4721
4722 /* Cool... it's the right one */
4723
willy tarreaub952e1d2005-12-18 01:31:20 +01004724 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004725 asession_temp = &local_asession;
4726
willy tarreaub952e1d2005-12-18 01:31:20 +01004727 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004728 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4729 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4730 }
4731 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4732 asession_temp->sessid[t->proxy->appsession_len] = 0;
4733 asession_temp->serverid = NULL;
4734
4735 /* only do insert, if lookup fails */
4736 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4737 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4738 Alert("Not enought Memory process_srv():asession:calloc().\n");
4739 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4740 return 0;
4741 }
4742 asession_temp->sessid = local_asession.sessid;
4743 asession_temp->serverid = local_asession.serverid;
4744 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004745 }/* end if (chtbl_lookup()) */
4746 else {
willy tarreau12350152005-12-18 01:03:27 +01004747 /* free wasted memory */
4748 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004749 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004750
willy tarreaub952e1d2005-12-18 01:31:20 +01004751 if (asession_temp->serverid == NULL) {
4752 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004753 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4754 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4755 }
4756 asession_temp->serverid[0] = '\0';
4757 }
4758
willy tarreaub952e1d2005-12-18 01:31:20 +01004759 if (asession_temp->serverid[0] == '\0')
4760 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004761
4762 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4763
4764#if defined(DEBUG_HASH)
4765 print_table(&(t->proxy->htbl_proxy));
4766#endif
4767 break;
4768 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004769 else {
4770 // fprintf(stderr,"Ignoring unknown cookie : ");
4771 // write(2, p1, p2-p1);
4772 // fprintf(stderr," = ");
4773 // write(2, p3, p4-p3);
4774 // fprintf(stderr,"\n");
4775 }
4776 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4777 } /* we're now at the end of the cookie value */
4778 } /* end of cookie processing */
4779
willy tarreau97f58572005-12-18 00:53:44 +01004780 /* check for any set-cookie in case we check for cacheability */
4781 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4782 (t->proxy->options & PR_O_CHK_CACHE) &&
4783 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4784 t->flags |= SN_SCK_ANY;
4785 }
4786
willy tarreau5cbea6f2005-12-17 12:48:26 +01004787 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004788 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004789 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004790
willy tarreau5cbea6f2005-12-17 12:48:26 +01004791 rep->h = rep->lr;
4792 } /* while (rep->lr < rep->r) */
4793
4794 /* end of header processing (even if incomplete) */
4795
willy tarreauef900ab2005-12-17 12:52:52 +01004796 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4797 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4798 * full. We cannot loop here since event_srv_read will disable it only if
4799 * rep->l == rlim-data
4800 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004801 FD_SET(t->srv_fd, StaticReadEvent);
4802 if (t->proxy->srvtimeout)
4803 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4804 else
4805 tv_eternity(&t->srexpire);
4806 }
willy tarreau0f7af912005-12-17 12:21:26 +01004807
willy tarreau8337c6b2005-12-17 13:41:01 +01004808 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004809 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004810 tv_eternity(&t->srexpire);
4811 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004812 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004813 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01004814 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004815 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004816 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004817 if (!(t->flags & SN_ERR_MASK))
4818 t->flags |= SN_ERR_SRVCL;
4819 if (!(t->flags & SN_FINST_MASK))
4820 t->flags |= SN_FINST_H;
willy tarreau704f32b2006-04-07 17:37:55 +02004821 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01004822 return 1;
4823 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004824 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004825 * since we are in header mode, if there's no space left for headers, we
4826 * won't be able to free more later, so the session will never terminate.
4827 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004828 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 +01004829 FD_CLR(t->srv_fd, StaticReadEvent);
4830 tv_eternity(&t->srexpire);
4831 shutdown(t->srv_fd, SHUT_RD);
4832 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004833 //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 +01004834 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004835 }
4836 /* read timeout : return a 504 to the client.
4837 */
4838 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4839 tv_eternity(&t->srexpire);
4840 tv_eternity(&t->swexpire);
4841 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004842 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01004843 t->srv_state = SV_STCLOSE;
4844 t->logs.status = 504;
4845 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004846 if (!(t->flags & SN_ERR_MASK))
4847 t->flags |= SN_ERR_SRVTO;
4848 if (!(t->flags & SN_FINST_MASK))
4849 t->flags |= SN_FINST_H;
willy tarreau704f32b2006-04-07 17:37:55 +02004850 /* TODO : check if there are pending connections on this server */
willy tarreau8337c6b2005-12-17 13:41:01 +01004851 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004852 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004853 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004854 /* FIXME!!! here, we don't want to switch to SHUTW if the
4855 * client shuts read too early, because we may still have
4856 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004857 * The side-effect is that if the client completely closes its
4858 * connection during SV_STHEADER, the connection to the server
4859 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004860 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004861 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004862 FD_CLR(t->srv_fd, StaticWriteEvent);
4863 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004864
4865 /* We must ensure that the read part is still alive when switching
4866 * to shutw */
4867 FD_SET(t->srv_fd, StaticReadEvent);
4868 if (t->proxy->srvtimeout)
4869 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4870
willy tarreau0f7af912005-12-17 12:21:26 +01004871 shutdown(t->srv_fd, SHUT_WR);
4872 t->srv_state = SV_STSHUTW;
4873 return 1;
4874 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004875 /* write timeout */
4876 /* FIXME!!! here, we don't want to switch to SHUTW if the
4877 * client shuts read too early, because we may still have
4878 * some work to do on the headers.
4879 */
4880 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4881 FD_CLR(t->srv_fd, StaticWriteEvent);
4882 tv_eternity(&t->swexpire);
4883 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004884 /* We must ensure that the read part is still alive when switching
4885 * to shutw */
4886 FD_SET(t->srv_fd, StaticReadEvent);
4887 if (t->proxy->srvtimeout)
4888 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4889
4890 /* We must ensure that the read part is still alive when switching
4891 * to shutw */
4892 FD_SET(t->srv_fd, StaticReadEvent);
4893 if (t->proxy->srvtimeout)
4894 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4895
willy tarreau036e1ce2005-12-17 13:46:33 +01004896 t->srv_state = SV_STSHUTW;
4897 if (!(t->flags & SN_ERR_MASK))
4898 t->flags |= SN_ERR_SRVTO;
4899 if (!(t->flags & SN_FINST_MASK))
4900 t->flags |= SN_FINST_H;
4901 return 1;
4902 }
willy tarreau0f7af912005-12-17 12:21:26 +01004903
4904 if (req->l == 0) {
4905 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4906 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4907 tv_eternity(&t->swexpire);
4908 }
4909 }
4910 else { /* client buffer not empty */
4911 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4912 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004913 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004914 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004915 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4916 t->srexpire = t->swexpire;
4917 }
willy tarreau0f7af912005-12-17 12:21:26 +01004918 else
4919 tv_eternity(&t->swexpire);
4920 }
4921 }
4922
willy tarreau5cbea6f2005-12-17 12:48:26 +01004923 /* be nice with the client side which would like to send a complete header
4924 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4925 * would read all remaining data at once ! The client should not write past rep->lr
4926 * when the server is in header state.
4927 */
4928 //return header_processed;
4929 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004930 }
4931 else if (s == SV_STDATA) {
4932 /* read or write error */
4933 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004934 tv_eternity(&t->srexpire);
4935 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004936 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004937 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01004938 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004939 if (!(t->flags & SN_ERR_MASK))
4940 t->flags |= SN_ERR_SRVCL;
4941 if (!(t->flags & SN_FINST_MASK))
4942 t->flags |= SN_FINST_D;
willy tarreau704f32b2006-04-07 17:37:55 +02004943 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01004944 return 1;
4945 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004946 /* last read, or end of client write */
4947 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004948 FD_CLR(t->srv_fd, StaticReadEvent);
4949 tv_eternity(&t->srexpire);
4950 shutdown(t->srv_fd, SHUT_RD);
4951 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004952 //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 +01004953 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004954 }
4955 /* end of client read and no more data to send */
4956 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4957 FD_CLR(t->srv_fd, StaticWriteEvent);
4958 tv_eternity(&t->swexpire);
4959 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004960 /* We must ensure that the read part is still alive when switching
4961 * to shutw */
4962 FD_SET(t->srv_fd, StaticReadEvent);
4963 if (t->proxy->srvtimeout)
4964 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4965
willy tarreaua41a8b42005-12-17 14:02:24 +01004966 t->srv_state = SV_STSHUTW;
4967 return 1;
4968 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004969 /* read timeout */
4970 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4971 FD_CLR(t->srv_fd, StaticReadEvent);
4972 tv_eternity(&t->srexpire);
4973 shutdown(t->srv_fd, SHUT_RD);
4974 t->srv_state = SV_STSHUTR;
4975 if (!(t->flags & SN_ERR_MASK))
4976 t->flags |= SN_ERR_SRVTO;
4977 if (!(t->flags & SN_FINST_MASK))
4978 t->flags |= SN_FINST_D;
4979 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004980 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004981 /* write timeout */
4982 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004983 FD_CLR(t->srv_fd, StaticWriteEvent);
4984 tv_eternity(&t->swexpire);
4985 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004986 /* We must ensure that the read part is still alive when switching
4987 * to shutw */
4988 FD_SET(t->srv_fd, StaticReadEvent);
4989 if (t->proxy->srvtimeout)
4990 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004991 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004992 if (!(t->flags & SN_ERR_MASK))
4993 t->flags |= SN_ERR_SRVTO;
4994 if (!(t->flags & SN_FINST_MASK))
4995 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004996 return 1;
4997 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004998
4999 /* recompute request time-outs */
5000 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005001 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5002 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5003 tv_eternity(&t->swexpire);
5004 }
5005 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005006 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01005007 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5008 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005009 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005010 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005011 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5012 t->srexpire = t->swexpire;
5013 }
willy tarreau0f7af912005-12-17 12:21:26 +01005014 else
5015 tv_eternity(&t->swexpire);
5016 }
5017 }
5018
willy tarreaub1ff9db2005-12-17 13:51:03 +01005019 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01005020 if (rep->l == BUFSIZE) { /* no room to read more data */
5021 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5022 FD_CLR(t->srv_fd, StaticReadEvent);
5023 tv_eternity(&t->srexpire);
5024 }
5025 }
5026 else {
5027 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5028 FD_SET(t->srv_fd, StaticReadEvent);
5029 if (t->proxy->srvtimeout)
5030 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5031 else
5032 tv_eternity(&t->srexpire);
5033 }
5034 }
5035
5036 return 0; /* other cases change nothing */
5037 }
5038 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005039 if (t->res_sw == RES_ERROR) {
5040 //FD_CLR(t->srv_fd, StaticWriteEvent);
5041 tv_eternity(&t->swexpire);
5042 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005043 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005044 //close(t->srv_fd);
5045 t->srv_state = SV_STCLOSE;
5046 if (!(t->flags & SN_ERR_MASK))
5047 t->flags |= SN_ERR_SRVCL;
5048 if (!(t->flags & SN_FINST_MASK))
5049 t->flags |= SN_FINST_D;
willy tarreau704f32b2006-04-07 17:37:55 +02005050 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005051 return 1;
5052 }
5053 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005054 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005055 tv_eternity(&t->swexpire);
5056 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005057 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005058 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005059 t->srv_state = SV_STCLOSE;
willy tarreau704f32b2006-04-07 17:37:55 +02005060 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01005061 return 1;
5062 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005063 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5064 //FD_CLR(t->srv_fd, StaticWriteEvent);
5065 tv_eternity(&t->swexpire);
5066 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005067 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005068 //close(t->srv_fd);
5069 t->srv_state = SV_STCLOSE;
5070 if (!(t->flags & SN_ERR_MASK))
5071 t->flags |= SN_ERR_SRVTO;
5072 if (!(t->flags & SN_FINST_MASK))
5073 t->flags |= SN_FINST_D;
willy tarreau704f32b2006-04-07 17:37:55 +02005074 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005075 return 1;
5076 }
willy tarreau0f7af912005-12-17 12:21:26 +01005077 else if (req->l == 0) {
5078 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5079 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5080 tv_eternity(&t->swexpire);
5081 }
5082 }
5083 else { /* buffer not empty */
5084 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5085 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005086 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005087 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005088 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5089 t->srexpire = t->swexpire;
5090 }
willy tarreau0f7af912005-12-17 12:21:26 +01005091 else
5092 tv_eternity(&t->swexpire);
5093 }
5094 }
5095 return 0;
5096 }
5097 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005098 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005099 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005100 tv_eternity(&t->srexpire);
5101 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005102 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005103 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005104 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005105 if (!(t->flags & SN_ERR_MASK))
5106 t->flags |= SN_ERR_SRVCL;
5107 if (!(t->flags & SN_FINST_MASK))
5108 t->flags |= SN_FINST_D;
willy tarreau704f32b2006-04-07 17:37:55 +02005109 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01005110 return 1;
5111 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005112 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
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;
willy tarreau704f32b2006-04-07 17:37:55 +02005119 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005120 return 1;
5121 }
5122 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5123 //FD_CLR(t->srv_fd, StaticReadEvent);
5124 tv_eternity(&t->srexpire);
5125 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005126 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005127 //close(t->srv_fd);
5128 t->srv_state = SV_STCLOSE;
5129 if (!(t->flags & SN_ERR_MASK))
5130 t->flags |= SN_ERR_SRVTO;
5131 if (!(t->flags & SN_FINST_MASK))
5132 t->flags |= SN_FINST_D;
willy tarreau704f32b2006-04-07 17:37:55 +02005133 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005134 return 1;
5135 }
willy tarreau0f7af912005-12-17 12:21:26 +01005136 else if (rep->l == BUFSIZE) { /* no room to read more data */
5137 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5138 FD_CLR(t->srv_fd, StaticReadEvent);
5139 tv_eternity(&t->srexpire);
5140 }
5141 }
5142 else {
5143 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5144 FD_SET(t->srv_fd, StaticReadEvent);
5145 if (t->proxy->srvtimeout)
5146 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5147 else
5148 tv_eternity(&t->srexpire);
5149 }
5150 }
5151 return 0;
5152 }
5153 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005154 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005155 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005156 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 +01005157 write(1, trash, len);
5158 }
5159 return 0;
5160 }
5161 return 0;
5162}
5163
5164
willy tarreau5cbea6f2005-12-17 12:48:26 +01005165/* Processes the client and server jobs of a session task, then
5166 * puts it back to the wait queue in a clean state, or
5167 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005168 * the time the task accepts to wait, or TIME_ETERNITY for
5169 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005170 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005171int process_session(struct task *t) {
5172 struct session *s = t->context;
5173 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005174
willy tarreau5cbea6f2005-12-17 12:48:26 +01005175 do {
5176 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005177 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005178 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005179 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005180 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005181 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005182 } while (fsm_resync);
5183
5184 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005185 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005186 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005187
willy tarreau5cbea6f2005-12-17 12:48:26 +01005188 tv_min(&min1, &s->crexpire, &s->cwexpire);
5189 tv_min(&min2, &s->srexpire, &s->swexpire);
5190 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005191 tv_min(&t->expire, &min1, &min2);
5192
5193 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005194 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005195
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005196#ifdef DEBUG_FULL
5197 /* DEBUG code : this should never ever happen, otherwise it indicates
5198 * that a task still has something to do and will provoke a quick loop.
5199 */
5200 if (tv_remain2(&now, &t->expire) <= 0)
5201 exit(100);
5202#endif
5203
willy tarreaub952e1d2005-12-18 01:31:20 +01005204 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005205 }
5206
willy tarreau5cbea6f2005-12-17 12:48:26 +01005207 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005208 actconn--;
5209
willy tarreau982249e2005-12-18 00:57:06 +01005210 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005211 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005212 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 +01005213 write(1, trash, len);
5214 }
5215
willy tarreau750a4722005-12-17 13:21:24 +01005216 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005217 if (s->rep != NULL)
5218 s->logs.bytes = s->rep->total;
5219
willy tarreau9fe663a2005-12-17 13:02:59 +01005220 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005221 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005222 sess_log(s);
5223
willy tarreau0f7af912005-12-17 12:21:26 +01005224 /* the task MUST not be in the run queue anymore */
5225 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005226 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005227 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005228 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005229}
5230
5231
5232
5233/*
5234 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005235 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005236 */
5237int process_chk(struct task *t) {
5238 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005239 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005240 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005241
willy tarreauef900ab2005-12-17 12:52:52 +01005242 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005243
willy tarreau25424f82006-03-19 19:37:48 +01005244 new_chk:
5245 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005246 if (fd < 0) { /* no check currently running */
5247 //fprintf(stderr, "process_chk: 2\n");
5248 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5249 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005250 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005251 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005252
5253 /* we don't send any health-checks when the proxy is stopped or when
5254 * the server should not be checked.
5255 */
5256 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005257 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5258 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005259 task_queue(t); /* restore t to its place in the task list */
5260 return tv_remain2(&now, &t->expire);
5261 }
5262
willy tarreau5cbea6f2005-12-17 12:48:26 +01005263 /* we'll initiate a new check */
5264 s->result = 0; /* no result yet */
5265 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005266 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005267 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5268 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5269 //fprintf(stderr, "process_chk: 3\n");
5270
willy tarreaua41a8b42005-12-17 14:02:24 +01005271 /* we'll connect to the check port on the server */
5272 sa = s->addr;
5273 sa.sin_port = htons(s->check_port);
5274
willy tarreau0174f312005-12-18 01:02:42 +01005275 /* allow specific binding :
5276 * - server-specific at first
5277 * - proxy-specific next
5278 */
5279 if (s->state & SRV_BIND_SRC) {
5280 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5281 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5282 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5283 s->proxy->id, s->id);
5284 s->result = -1;
5285 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005286 }
willy tarreau0174f312005-12-18 01:02:42 +01005287 else if (s->proxy->options & PR_O_BIND_SRC) {
5288 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5289 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5290 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5291 s->proxy->id);
5292 s->result = -1;
5293 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005294 }
willy tarreau0174f312005-12-18 01:02:42 +01005295
5296 if (!s->result) {
5297 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5298 /* OK, connection in progress or established */
5299
5300 //fprintf(stderr, "process_chk: 4\n");
5301
5302 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5303 fdtab[fd].owner = t;
5304 fdtab[fd].read = &event_srv_chk_r;
5305 fdtab[fd].write = &event_srv_chk_w;
5306 fdtab[fd].state = FD_STCONN; /* connection in progress */
5307 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005308#ifdef DEBUG_FULL
5309 assert (!FD_ISSET(fd, StaticReadEvent));
5310#endif
willy tarreau0174f312005-12-18 01:02:42 +01005311 fd_insert(fd);
5312 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5313 tv_delayfrom(&t->expire, &now, s->inter);
5314 task_queue(t); /* restore t to its place in the task list */
5315 return tv_remain(&now, &t->expire);
5316 }
5317 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5318 s->result = -1; /* a real error */
5319 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005320 }
5321 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005322 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005323 }
5324
5325 if (!s->result) { /* nothing done */
5326 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005327 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5328 tv_delayfrom(&t->expire, &t->expire, s->inter);
5329 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005330 }
5331
5332 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005333 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005334 s->health--; /* still good */
5335 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005336 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005337 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005338 recount_servers(s->proxy);
5339 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5340 s->state & SRV_BACKUP ? "Backup " : "",
5341 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5342 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5343 send_log(s->proxy, LOG_ALERT,
5344 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5345 s->state & SRV_BACKUP ? "Backup " : "",
5346 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5347 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreauef900ab2005-12-17 12:52:52 +01005348
willy tarreau62084d42006-03-24 18:57:41 +01005349 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
willy tarreaudd07e972005-12-18 00:48:48 +01005350 Alert("Proxy %s has no server available !\n", s->proxy->id);
5351 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5352 }
5353 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005354 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005355 }
5356
5357 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005358 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005359 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5360 tv_delayfrom(&t->expire, &t->expire, s->inter);
5361 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005362 }
5363 else {
5364 //fprintf(stderr, "process_chk: 8\n");
5365 /* there was a test running */
5366 if (s->result > 0) { /* good server detected */
5367 //fprintf(stderr, "process_chk: 9\n");
5368 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005369 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02005370 s->state |= SRV_RUNNING;
5371
willy tarreau535ae7a2005-12-17 12:58:00 +01005372 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005373 recount_servers(s->proxy);
5374 Warning("%sServer %s/%s UP. %d active and %d backup servers online.%s\n",
5375 s->state & SRV_BACKUP ? "Backup " : "",
5376 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5377 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5378 send_log(s->proxy, LOG_NOTICE,
5379 "%sServer %s/%s is UP. %d active and %d backup servers online.%s\n",
5380 s->state & SRV_BACKUP ? "Backup " : "",
5381 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5382 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreau535ae7a2005-12-17 12:58:00 +01005383 }
willy tarreauef900ab2005-12-17 12:52:52 +01005384
willy tarreaue47c8d72005-12-17 12:55:52 +01005385 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005386 }
willy tarreauef900ab2005-12-17 12:52:52 +01005387 s->curfd = -1; /* no check running anymore */
5388 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005389 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005390 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5391 tv_delayfrom(&t->expire, &t->expire, s->inter);
5392 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005393 }
5394 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5395 //fprintf(stderr, "process_chk: 10\n");
5396 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005397 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005398 s->health--; /* still good */
5399 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005400 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005401
willy tarreau62084d42006-03-24 18:57:41 +01005402 if (s->health == s->rise) {
5403 recount_servers(s->proxy);
5404 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5405 s->state & SRV_BACKUP ? "Backup " : "",
5406 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5407 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5408 send_log(s->proxy, LOG_ALERT,
5409 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5410 s->state & SRV_BACKUP ? "Backup " : "",
5411 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5412 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5413
5414 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5415 Alert("Proxy %s has no server available !\n", s->proxy->id);
5416 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5417 }
5418 }
willy tarreauef900ab2005-12-17 12:52:52 +01005419
willy tarreau5cbea6f2005-12-17 12:48:26 +01005420 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005421 }
5422 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005423 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005424 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005425 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5426 tv_delayfrom(&t->expire, &t->expire, s->inter);
5427 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005428 }
5429 /* if result is 0 and there's no timeout, we have to wait again */
5430 }
5431 //fprintf(stderr, "process_chk: 11\n");
5432 s->result = 0;
5433 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005434 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005435}
5436
5437
willy tarreau5cbea6f2005-12-17 12:48:26 +01005438
willy tarreau0f7af912005-12-17 12:21:26 +01005439#if STATTIME > 0
5440int stats(void);
5441#endif
5442
5443/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005444 * This does 4 things :
5445 * - wake up all expired tasks
5446 * - call all runnable tasks
5447 * - call maintain_proxies() to enable/disable the listeners
5448 * - return the delay till next event in ms, -1 = wait indefinitely
5449 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5450 *
willy tarreau0f7af912005-12-17 12:21:26 +01005451 */
5452
willy tarreau1c2ad212005-12-18 01:11:29 +01005453int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005454 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005455 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005456 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005457
willy tarreaub952e1d2005-12-18 01:31:20 +01005458 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005459
willy tarreau1c2ad212005-12-18 01:11:29 +01005460 /* look for expired tasks and add them to the run queue.
5461 */
5462 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5463 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5464 tnext = t->next;
5465 if (t->state & TASK_RUNNING)
5466 continue;
5467
willy tarreaub952e1d2005-12-18 01:31:20 +01005468 if (tv_iseternity(&t->expire))
5469 continue;
5470
willy tarreau1c2ad212005-12-18 01:11:29 +01005471 /* wakeup expired entries. It doesn't matter if they are
5472 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005473 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005474 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005475 task_wakeup(&rq, t);
5476 }
5477 else {
5478 /* first non-runnable task. Use its expiration date as an upper bound */
5479 int temp_time = tv_remain(&now, &t->expire);
5480 if (temp_time)
5481 next_time = temp_time;
5482 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005483 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005484 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005485
willy tarreau1c2ad212005-12-18 01:11:29 +01005486 /* process each task in the run queue now. Each task may be deleted
5487 * since we only use tnext.
5488 */
5489 tnext = rq;
5490 while ((t = tnext) != NULL) {
5491 int temp_time;
5492
5493 tnext = t->rqnext;
5494 task_sleep(&rq, t);
5495 temp_time = t->process(t);
5496 next_time = MINTIME(temp_time, next_time);
5497 }
5498
5499 /* maintain all proxies in a consistent state. This should quickly become a task */
5500 time2 = maintain_proxies();
5501 return MINTIME(time2, next_time);
5502}
5503
5504
5505#if defined(ENABLE_EPOLL)
5506
5507/*
5508 * Main epoll() loop.
5509 */
5510
5511/* does 3 actions :
5512 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5513 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5514 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5515 *
5516 * returns 0 if initialization failed, !0 otherwise.
5517 */
5518
5519int epoll_loop(int action) {
5520 int next_time;
5521 int status;
5522 int fd;
5523
5524 int fds, count;
5525 int pr, pw, sr, sw;
5526 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5527 struct epoll_event ev;
5528
5529 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005530 static struct epoll_event *epoll_events = NULL;
5531 static int epoll_fd;
5532
5533 if (action == POLL_LOOP_ACTION_INIT) {
5534 epoll_fd = epoll_create(global.maxsock + 1);
5535 if (epoll_fd < 0)
5536 return 0;
5537 else {
5538 epoll_events = (struct epoll_event*)
5539 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5540 PrevReadEvent = (fd_set *)
5541 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5542 PrevWriteEvent = (fd_set *)
5543 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005544 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005545 return 1;
5546 }
5547 else if (action == POLL_LOOP_ACTION_CLEAN) {
5548 if (PrevWriteEvent) free(PrevWriteEvent);
5549 if (PrevReadEvent) free(PrevReadEvent);
5550 if (epoll_events) free(epoll_events);
5551 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005552 epoll_fd = 0;
5553 return 1;
5554 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005555
willy tarreau1c2ad212005-12-18 01:11:29 +01005556 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005557
willy tarreau1c2ad212005-12-18 01:11:29 +01005558 tv_now(&now);
5559
5560 while (1) {
5561 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005562
5563 /* stop when there's no connection left and we don't allow them anymore */
5564 if (!actconn && listeners == 0)
5565 break;
5566
willy tarreau0f7af912005-12-17 12:21:26 +01005567#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005568 {
5569 int time2;
5570 time2 = stats();
5571 next_time = MINTIME(time2, next_time);
5572 }
willy tarreau0f7af912005-12-17 12:21:26 +01005573#endif
5574
willy tarreau1c2ad212005-12-18 01:11:29 +01005575 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5576
5577 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5578 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5579
5580 if ((ro^rn) | (wo^wn)) {
5581 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5582#define FDSETS_ARE_INT_ALIGNED
5583#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005584
willy tarreauad90a0c2005-12-18 01:09:15 +01005585#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5586#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005587 pr = (ro >> count) & 1;
5588 pw = (wo >> count) & 1;
5589 sr = (rn >> count) & 1;
5590 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005591#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005592 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5593 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5594 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5595 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005596#endif
5597#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005598 pr = FD_ISSET(fd, PrevReadEvent);
5599 pw = FD_ISSET(fd, PrevWriteEvent);
5600 sr = FD_ISSET(fd, StaticReadEvent);
5601 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005602#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005603 if (!((sr^pr) | (sw^pw)))
5604 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005605
willy tarreau1c2ad212005-12-18 01:11:29 +01005606 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5607 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005608
willy tarreaub952e1d2005-12-18 01:31:20 +01005609#ifdef EPOLL_CTL_MOD_WORKAROUND
5610 /* I encountered a rarely reproducible problem with
5611 * EPOLL_CTL_MOD where a modified FD (systematically
5612 * the one in epoll_events[0], fd#7) would sometimes
5613 * be set EPOLL_OUT while asked for a read ! This is
5614 * with the 2.4 epoll patch. The workaround is to
5615 * delete then recreate in case of modification.
5616 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5617 * nor RHEL kernels.
5618 */
5619
5620 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5621 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5622
5623 if ((sr | sw))
5624 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5625#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005626 if ((pr | pw)) {
5627 /* the file-descriptor already exists... */
5628 if ((sr | sw)) {
5629 /* ...and it will still exist */
5630 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5631 // perror("epoll_ctl(MOD)");
5632 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005633 }
5634 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005635 /* ...and it will be removed */
5636 if (fdtab[fd].state != FD_STCLOSE &&
5637 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5638 // perror("epoll_ctl(DEL)");
5639 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005640 }
5641 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005642 } else {
5643 /* the file-descriptor did not exist, let's add it */
5644 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5645 // perror("epoll_ctl(ADD)");
5646 // exit(1);
5647 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005648 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005649#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005650 }
5651 ((int*)PrevReadEvent)[fds] = rn;
5652 ((int*)PrevWriteEvent)[fds] = wn;
5653 }
5654 }
5655
5656 /* now let's wait for events */
5657 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5658 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005659
willy tarreau1c2ad212005-12-18 01:11:29 +01005660 for (count = 0; count < status; count++) {
5661 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01005662
5663 if (FD_ISSET(fd, StaticReadEvent)) {
5664 if (fdtab[fd].state == FD_STCLOSE)
5665 continue;
5666 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5667 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005668 }
willy tarreau05be12b2006-03-19 19:35:00 +01005669
5670 if (FD_ISSET(fd, StaticWriteEvent)) {
5671 if (fdtab[fd].state == FD_STCLOSE)
5672 continue;
5673 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5674 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005675 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005676 }
5677 }
5678 return 1;
5679}
5680#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005681
willy tarreauad90a0c2005-12-18 01:09:15 +01005682
willy tarreau5cbea6f2005-12-17 12:48:26 +01005683
willy tarreau1c2ad212005-12-18 01:11:29 +01005684#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005685
willy tarreau1c2ad212005-12-18 01:11:29 +01005686/*
5687 * Main poll() loop.
5688 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005689
willy tarreau1c2ad212005-12-18 01:11:29 +01005690/* does 3 actions :
5691 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5692 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5693 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5694 *
5695 * returns 0 if initialization failed, !0 otherwise.
5696 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005697
willy tarreau1c2ad212005-12-18 01:11:29 +01005698int poll_loop(int action) {
5699 int next_time;
5700 int status;
5701 int fd, nbfd;
5702
5703 int fds, count;
5704 int sr, sw;
5705 unsigned rn, wn; /* read new, write new */
5706
5707 /* private data */
5708 static struct pollfd *poll_events = NULL;
5709
5710 if (action == POLL_LOOP_ACTION_INIT) {
5711 poll_events = (struct pollfd*)
5712 calloc(1, sizeof(struct pollfd) * global.maxsock);
5713 return 1;
5714 }
5715 else if (action == POLL_LOOP_ACTION_CLEAN) {
5716 if (poll_events)
5717 free(poll_events);
5718 return 1;
5719 }
5720
5721 /* OK, it's POLL_LOOP_ACTION_RUN */
5722
5723 tv_now(&now);
5724
5725 while (1) {
5726 next_time = process_runnable_tasks();
5727
5728 /* stop when there's no connection left and we don't allow them anymore */
5729 if (!actconn && listeners == 0)
5730 break;
5731
5732#if STATTIME > 0
5733 {
5734 int time2;
5735 time2 = stats();
5736 next_time = MINTIME(time2, next_time);
5737 }
5738#endif
5739
5740
5741 nbfd = 0;
5742 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5743
5744 rn = ((int*)StaticReadEvent)[fds];
5745 wn = ((int*)StaticWriteEvent)[fds];
5746
5747 if ((rn|wn)) {
5748 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5749#define FDSETS_ARE_INT_ALIGNED
5750#ifdef FDSETS_ARE_INT_ALIGNED
5751
5752#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5753#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5754 sr = (rn >> count) & 1;
5755 sw = (wn >> count) & 1;
5756#else
5757 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5758 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5759#endif
5760#else
5761 sr = FD_ISSET(fd, StaticReadEvent);
5762 sw = FD_ISSET(fd, StaticWriteEvent);
5763#endif
5764 if ((sr|sw)) {
5765 poll_events[nbfd].fd = fd;
5766 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5767 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005768 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005769 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005770 }
5771 }
5772
5773 /* now let's wait for events */
5774 status = poll(poll_events, nbfd, next_time);
5775 tv_now(&now);
5776
5777 for (count = 0; status > 0 && count < nbfd; count++) {
5778 fd = poll_events[count].fd;
5779
5780 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5781 continue;
5782
5783 /* ok, we found one active fd */
5784 status--;
5785
willy tarreau05be12b2006-03-19 19:35:00 +01005786 if (FD_ISSET(fd, StaticReadEvent)) {
5787 if (fdtab[fd].state == FD_STCLOSE)
5788 continue;
5789 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5790 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005791 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005792
willy tarreau05be12b2006-03-19 19:35:00 +01005793 if (FD_ISSET(fd, StaticWriteEvent)) {
5794 if (fdtab[fd].state == FD_STCLOSE)
5795 continue;
5796 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5797 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005798 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005799 }
5800 }
5801 return 1;
5802}
willy tarreauad90a0c2005-12-18 01:09:15 +01005803#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005804
willy tarreauad90a0c2005-12-18 01:09:15 +01005805
willy tarreauad90a0c2005-12-18 01:09:15 +01005806
willy tarreau1c2ad212005-12-18 01:11:29 +01005807/*
5808 * Main select() loop.
5809 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005810
willy tarreau1c2ad212005-12-18 01:11:29 +01005811/* does 3 actions :
5812 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5813 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5814 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5815 *
5816 * returns 0 if initialization failed, !0 otherwise.
5817 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005818
willy tarreauad90a0c2005-12-18 01:09:15 +01005819
willy tarreau1c2ad212005-12-18 01:11:29 +01005820int select_loop(int action) {
5821 int next_time;
5822 int status;
5823 int fd,i;
5824 struct timeval delta;
5825 int readnotnull, writenotnull;
5826 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005827
willy tarreau1c2ad212005-12-18 01:11:29 +01005828 if (action == POLL_LOOP_ACTION_INIT) {
5829 ReadEvent = (fd_set *)
5830 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5831 WriteEvent = (fd_set *)
5832 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5833 return 1;
5834 }
5835 else if (action == POLL_LOOP_ACTION_CLEAN) {
5836 if (WriteEvent) free(WriteEvent);
5837 if (ReadEvent) free(ReadEvent);
5838 return 1;
5839 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005840
willy tarreau1c2ad212005-12-18 01:11:29 +01005841 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005842
willy tarreau1c2ad212005-12-18 01:11:29 +01005843 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005844
willy tarreau1c2ad212005-12-18 01:11:29 +01005845 while (1) {
5846 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005847
willy tarreau1c2ad212005-12-18 01:11:29 +01005848 /* stop when there's no connection left and we don't allow them anymore */
5849 if (!actconn && listeners == 0)
5850 break;
5851
5852#if STATTIME > 0
5853 {
5854 int time2;
5855 time2 = stats();
5856 next_time = MINTIME(time2, next_time);
5857 }
5858#endif
5859
willy tarreau1c2ad212005-12-18 01:11:29 +01005860 if (next_time > 0) { /* FIXME */
5861 /* Convert to timeval */
5862 /* to avoid eventual select loops due to timer precision */
5863 next_time += SCHEDULER_RESOLUTION;
5864 delta.tv_sec = next_time / 1000;
5865 delta.tv_usec = (next_time % 1000) * 1000;
5866 }
5867 else if (next_time == 0) { /* allow select to return immediately when needed */
5868 delta.tv_sec = delta.tv_usec = 0;
5869 }
5870
5871
5872 /* let's restore fdset state */
5873
5874 readnotnull = 0; writenotnull = 0;
5875 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5876 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5877 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5878 }
5879
5880 // /* just a verification code, needs to be removed for performance */
5881 // for (i=0; i<maxfd; i++) {
5882 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5883 // abort();
5884 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5885 // abort();
5886 //
5887 // }
5888
5889 status = select(maxfd,
5890 readnotnull ? ReadEvent : NULL,
5891 writenotnull ? WriteEvent : NULL,
5892 NULL,
5893 (next_time >= 0) ? &delta : NULL);
5894
5895 /* this is an experiment on the separation of the select work */
5896 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5897 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5898
5899 tv_now(&now);
5900
5901 if (status > 0) { /* must proceed with events */
5902
5903 int fds;
5904 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005905
willy tarreau1c2ad212005-12-18 01:11:29 +01005906 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5907 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5908 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5909
5910 /* if we specify read first, the accepts and zero reads will be
5911 * seen first. Moreover, system buffers will be flushed faster.
5912 */
willy tarreau05be12b2006-03-19 19:35:00 +01005913 if (FD_ISSET(fd, ReadEvent)) {
5914 if (fdtab[fd].state == FD_STCLOSE)
5915 continue;
5916 fdtab[fd].read(fd);
5917 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005918
willy tarreau05be12b2006-03-19 19:35:00 +01005919 if (FD_ISSET(fd, WriteEvent)) {
5920 if (fdtab[fd].state == FD_STCLOSE)
5921 continue;
5922 fdtab[fd].write(fd);
5923 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005924 }
5925 }
5926 else {
5927 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005928 }
willy tarreau0f7af912005-12-17 12:21:26 +01005929 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005930 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005931}
5932
5933
5934#if STATTIME > 0
5935/*
5936 * Display proxy statistics regularly. It is designed to be called from the
5937 * select_loop().
5938 */
5939int stats(void) {
5940 static int lines;
5941 static struct timeval nextevt;
5942 static struct timeval lastevt;
5943 static struct timeval starttime = {0,0};
5944 unsigned long totaltime, deltatime;
5945 int ret;
5946
willy tarreau750a4722005-12-17 13:21:24 +01005947 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005948 deltatime = (tv_diff(&lastevt, &now)?:1);
5949 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005950
willy tarreau9fe663a2005-12-17 13:02:59 +01005951 if (global.mode & MODE_STATS) {
5952 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005953 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005954 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5955 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005956 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005957 actconn, totalconn,
5958 stats_tsk_new, stats_tsk_good,
5959 stats_tsk_left, stats_tsk_right,
5960 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5961 }
5962 }
5963
5964 tv_delayfrom(&nextevt, &now, STATTIME);
5965
5966 lastevt=now;
5967 }
5968 ret = tv_remain(&now, &nextevt);
5969 return ret;
5970}
5971#endif
5972
5973
5974/*
5975 * this function enables proxies when there are enough free sessions,
5976 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005977 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005978 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005979 */
5980static int maintain_proxies(void) {
5981 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005982 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005983 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005984
5985 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005986 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005987
5988 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005989 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005990 while (p) {
5991 if (p->nbconn < p->maxconn) {
5992 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005993 for (l = p->listen; l != NULL; l = l->next) {
5994 FD_SET(l->fd, StaticReadEvent);
5995 }
willy tarreau0f7af912005-12-17 12:21:26 +01005996 p->state = PR_STRUN;
5997 }
5998 }
5999 else {
6000 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006001 for (l = p->listen; l != NULL; l = l->next) {
6002 FD_CLR(l->fd, StaticReadEvent);
6003 }
willy tarreau0f7af912005-12-17 12:21:26 +01006004 p->state = PR_STIDLE;
6005 }
6006 }
6007 p = p->next;
6008 }
6009 }
6010 else { /* block all proxies */
6011 while (p) {
6012 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006013 for (l = p->listen; l != NULL; l = l->next) {
6014 FD_CLR(l->fd, StaticReadEvent);
6015 }
willy tarreau0f7af912005-12-17 12:21:26 +01006016 p->state = PR_STIDLE;
6017 }
6018 p = p->next;
6019 }
6020 }
6021
willy tarreau5cbea6f2005-12-17 12:48:26 +01006022 if (stopping) {
6023 p = proxy;
6024 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01006025 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006026 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006027 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006028 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006029 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006030 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006031
willy tarreaua41a8b42005-12-17 14:02:24 +01006032 for (l = p->listen; l != NULL; l = l->next) {
6033 fd_delete(l->fd);
6034 listeners--;
6035 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006036 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006037 }
6038 else {
6039 tleft = MINTIME(t, tleft);
6040 }
6041 }
6042 p = p->next;
6043 }
6044 }
6045 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006046}
6047
6048/*
6049 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006050 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6051 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006052 */
6053static void soft_stop(void) {
6054 struct proxy *p;
6055
6056 stopping = 1;
6057 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006058 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006059 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006060 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006061 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006062 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006063 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006064 }
willy tarreau0f7af912005-12-17 12:21:26 +01006065 p = p->next;
6066 }
6067}
6068
willy tarreaudbd3bef2006-01-20 19:35:18 +01006069static void pause_proxy(struct proxy *p) {
6070 struct listener *l;
6071 for (l = p->listen; l != NULL; l = l->next) {
6072 shutdown(l->fd, SHUT_RD);
6073 FD_CLR(l->fd, StaticReadEvent);
6074 p->state = PR_STPAUSED;
6075 }
6076}
6077
6078/*
6079 * This function temporarily disables listening so that another new instance
6080 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006081 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006082 * the proxy, or a SIGTTIN can be sent to listen again.
6083 */
6084static void pause_proxies(void) {
6085 struct proxy *p;
6086
6087 p = proxy;
6088 tv_now(&now); /* else, the old time before select will be used */
6089 while (p) {
6090 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6091 Warning("Pausing proxy %s.\n", p->id);
6092 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6093 pause_proxy(p);
6094 }
6095 p = p->next;
6096 }
6097}
6098
6099
6100/*
6101 * This function reactivates listening. This can be used after a call to
6102 * sig_pause(), for example when a new instance has failed starting up.
6103 * It is designed to be called upon reception of a SIGTTIN.
6104 */
6105static void listen_proxies(void) {
6106 struct proxy *p;
6107 struct listener *l;
6108
6109 p = proxy;
6110 tv_now(&now); /* else, the old time before select will be used */
6111 while (p) {
6112 if (p->state == PR_STPAUSED) {
6113 Warning("Enabling proxy %s.\n", p->id);
6114 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6115
6116 for (l = p->listen; l != NULL; l = l->next) {
6117 if (listen(l->fd, p->maxconn) == 0) {
6118 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6119 FD_SET(l->fd, StaticReadEvent);
6120 p->state = PR_STRUN;
6121 }
6122 else
6123 p->state = PR_STIDLE;
6124 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006125 int port;
6126
6127 if (l->addr.ss_family == AF_INET6)
6128 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6129 else
6130 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6131
willy tarreaudbd3bef2006-01-20 19:35:18 +01006132 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006133 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006134 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006135 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006136 /* Another port might have been enabled. Let's stop everything. */
6137 pause_proxy(p);
6138 break;
6139 }
6140 }
6141 }
6142 p = p->next;
6143 }
6144}
6145
6146
willy tarreau0f7af912005-12-17 12:21:26 +01006147/*
6148 * upon SIGUSR1, let's have a soft stop.
6149 */
6150void sig_soft_stop(int sig) {
6151 soft_stop();
6152 signal(sig, SIG_IGN);
6153}
6154
willy tarreaudbd3bef2006-01-20 19:35:18 +01006155/*
6156 * upon SIGTTOU, we pause everything
6157 */
6158void sig_pause(int sig) {
6159 pause_proxies();
6160 signal(sig, sig_pause);
6161}
willy tarreau0f7af912005-12-17 12:21:26 +01006162
willy tarreau8337c6b2005-12-17 13:41:01 +01006163/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006164 * upon SIGTTIN, let's have a soft stop.
6165 */
6166void sig_listen(int sig) {
6167 listen_proxies();
6168 signal(sig, sig_listen);
6169}
6170
6171/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006172 * this function dumps every server's state when the process receives SIGHUP.
6173 */
6174void sig_dump_state(int sig) {
6175 struct proxy *p = proxy;
6176
6177 Warning("SIGHUP received, dumping servers states.\n");
6178 while (p) {
6179 struct server *s = p->srv;
6180
6181 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
6182 while (s) {
6183 if (s->state & SRV_RUNNING) {
willy tarreaufd6dfe72006-03-19 19:38:19 +01006184 Warning("SIGHUP: Server %s/%s is UP.\n", p->id, s->id);
6185 send_log(p, LOG_NOTICE, "SIGUP: Server %s/%s is UP.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006186 }
6187 else {
willy tarreaufd6dfe72006-03-19 19:38:19 +01006188 Warning("SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
6189 send_log(p, LOG_NOTICE, "SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006190 }
6191 s = s->next;
6192 }
willy tarreaudd07e972005-12-18 00:48:48 +01006193
willy tarreau62084d42006-03-24 18:57:41 +01006194 if (p->srv_act == 0) {
6195 if (p->srv_bck) {
6196 Warning("SIGHUP: Proxy %s is running on backup servers !\n", p->id);
6197 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s is running on backup servers !\n", p->id);
6198 } else {
6199 Warning("SIGHUP: Proxy %s has no server available !\n", p->id);
6200 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s has no server available !\n", p->id);
6201 }
6202 }
willy tarreaudd07e972005-12-18 00:48:48 +01006203
willy tarreau8337c6b2005-12-17 13:41:01 +01006204 p = p->next;
6205 }
6206 signal(sig, sig_dump_state);
6207}
6208
willy tarreau0f7af912005-12-17 12:21:26 +01006209void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006210 struct task *t, *tnext;
6211 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006212
willy tarreau5cbea6f2005-12-17 12:48:26 +01006213 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
6214 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
6215 tnext = t->next;
6216 s = t->context;
6217 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6218 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6219 "req=%d, rep=%d, clifd=%d\n",
6220 s, tv_remain(&now, &t->expire),
6221 s->cli_state,
6222 s->srv_state,
6223 FD_ISSET(s->cli_fd, StaticReadEvent),
6224 FD_ISSET(s->cli_fd, StaticWriteEvent),
6225 FD_ISSET(s->srv_fd, StaticReadEvent),
6226 FD_ISSET(s->srv_fd, StaticWriteEvent),
6227 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6228 );
willy tarreau0f7af912005-12-17 12:21:26 +01006229 }
willy tarreau12350152005-12-18 01:03:27 +01006230}
6231
willy tarreau64a3cc32005-12-18 01:13:11 +01006232#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006233static void fast_stop(void)
6234{
6235 struct proxy *p;
6236 p = proxy;
6237 while (p) {
6238 p->grace = 0;
6239 p = p->next;
6240 }
6241 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006242}
6243
willy tarreau12350152005-12-18 01:03:27 +01006244void sig_int(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}
6254
6255void sig_term(int sig) {
6256 /* This would normally be a hard stop,
6257 but we want to be sure about deallocation,
6258 and so on, so we do a soft stop with
6259 0 GRACE time
6260 */
6261 fast_stop();
6262 /* If we are killed twice, we decide to die*/
6263 signal(sig, SIG_DFL);
6264}
willy tarreau64a3cc32005-12-18 01:13:11 +01006265#endif
willy tarreau12350152005-12-18 01:03:27 +01006266
willy tarreauc1f47532005-12-18 01:08:26 +01006267/* returns the pointer to an error in the replacement string, or NULL if OK */
6268char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006269 struct hdr_exp *exp;
6270
willy tarreauc1f47532005-12-18 01:08:26 +01006271 if (replace != NULL) {
6272 char *err;
6273 err = check_replace_string(replace);
6274 if (err)
6275 return err;
6276 }
6277
willy tarreaue39cd132005-12-17 13:00:18 +01006278 while (*head != NULL)
6279 head = &(*head)->next;
6280
6281 exp = calloc(1, sizeof(struct hdr_exp));
6282
6283 exp->preg = preg;
6284 exp->replace = replace;
6285 exp->action = action;
6286 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006287
6288 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006289}
6290
willy tarreau9fe663a2005-12-17 13:02:59 +01006291
willy tarreau0f7af912005-12-17 12:21:26 +01006292/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006293 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006294 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006295int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006296
willy tarreau9fe663a2005-12-17 13:02:59 +01006297 if (!strcmp(args[0], "global")) { /* new section */
6298 /* no option, nothing special to do */
6299 return 0;
6300 }
6301 else if (!strcmp(args[0], "daemon")) {
6302 global.mode |= MODE_DAEMON;
6303 }
6304 else if (!strcmp(args[0], "debug")) {
6305 global.mode |= MODE_DEBUG;
6306 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006307 else if (!strcmp(args[0], "noepoll")) {
6308 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6309 }
6310 else if (!strcmp(args[0], "nopoll")) {
6311 cfg_polling_mechanism &= ~POLL_USE_POLL;
6312 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006313 else if (!strcmp(args[0], "quiet")) {
6314 global.mode |= MODE_QUIET;
6315 }
6316 else if (!strcmp(args[0], "stats")) {
6317 global.mode |= MODE_STATS;
6318 }
6319 else if (!strcmp(args[0], "uid")) {
6320 if (global.uid != 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 tarreau9fe663a2005-12-17 13:02:59 +01006326 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006327 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006328 global.uid = atol(args[1]);
6329 }
6330 else if (!strcmp(args[0], "gid")) {
6331 if (global.gid != 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 tarreau0f7af912005-12-17 12:21:26 +01006337 return -1;
6338 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006339 global.gid = atol(args[1]);
6340 }
6341 else if (!strcmp(args[0], "nbproc")) {
6342 if (global.nbproc != 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.nbproc = atol(args[1]);
6351 }
6352 else if (!strcmp(args[0], "maxconn")) {
6353 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006354 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006355 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006356 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006357 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006358 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006359 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006360 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006361 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006362#ifdef SYSTEM_MAXCONN
6363 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6364 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);
6365 global.maxconn = DEFAULT_MAXCONN;
6366 }
6367#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006368 }
willy tarreaub1285d52005-12-18 01:20:14 +01006369 else if (!strcmp(args[0], "ulimit-n")) {
6370 if (global.rlimit_nofile != 0) {
6371 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6372 return 0;
6373 }
6374 if (*(args[1]) == 0) {
6375 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6376 return -1;
6377 }
6378 global.rlimit_nofile = atol(args[1]);
6379 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006380 else if (!strcmp(args[0], "chroot")) {
6381 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006382 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006383 return 0;
6384 }
6385 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006386 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006387 return -1;
6388 }
6389 global.chroot = strdup(args[1]);
6390 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006391 else if (!strcmp(args[0], "pidfile")) {
6392 if (global.pidfile != NULL) {
6393 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6394 return 0;
6395 }
6396 if (*(args[1]) == 0) {
6397 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6398 return -1;
6399 }
6400 global.pidfile = strdup(args[1]);
6401 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006402 else if (!strcmp(args[0], "log")) { /* syslog server address */
6403 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006404 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006405
6406 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006407 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006408 return -1;
6409 }
6410
6411 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6412 if (!strcmp(log_facilities[facility], args[2]))
6413 break;
6414
6415 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006416 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006417 exit(1);
6418 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006419
6420 level = 7; /* max syslog level = debug */
6421 if (*(args[3])) {
6422 while (level >= 0 && strcmp(log_levels[level], args[3]))
6423 level--;
6424 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006425 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006426 exit(1);
6427 }
6428 }
6429
willy tarreau9fe663a2005-12-17 13:02:59 +01006430 sa = str2sa(args[1]);
6431 if (!sa->sin_port)
6432 sa->sin_port = htons(SYSLOG_PORT);
6433
6434 if (global.logfac1 == -1) {
6435 global.logsrv1 = *sa;
6436 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006437 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006438 }
6439 else if (global.logfac2 == -1) {
6440 global.logsrv2 = *sa;
6441 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006442 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006443 }
6444 else {
6445 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6446 return -1;
6447 }
6448
6449 }
6450 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006451 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006452 return -1;
6453 }
6454 return 0;
6455}
6456
6457
willy tarreaua41a8b42005-12-17 14:02:24 +01006458void init_default_instance() {
6459 memset(&defproxy, 0, sizeof(defproxy));
6460 defproxy.mode = PR_MODE_TCP;
6461 defproxy.state = PR_STNEW;
6462 defproxy.maxconn = cfg_maxpconn;
6463 defproxy.conn_retries = CONN_RETRIES;
6464 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6465}
6466
willy tarreau9fe663a2005-12-17 13:02:59 +01006467/*
6468 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6469 */
6470int cfg_parse_listen(char *file, int linenum, char **args) {
6471 static struct proxy *curproxy = NULL;
6472 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006473 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006474 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006475
6476 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006477 if (!*args[1]) {
6478 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6479 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006480 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006481 return -1;
6482 }
6483
6484 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006485 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006486 return -1;
6487 }
6488 curproxy->next = proxy;
6489 proxy = curproxy;
6490 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006491
6492 /* parse the listener address if any */
6493 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006494 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006495 if (!curproxy->listen)
6496 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006497 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01006498 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006499
willy tarreau9fe663a2005-12-17 13:02:59 +01006500 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006501 curproxy->state = defproxy.state;
6502 curproxy->maxconn = defproxy.maxconn;
6503 curproxy->conn_retries = defproxy.conn_retries;
6504 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006505
6506 if (defproxy.check_req)
6507 curproxy->check_req = strdup(defproxy.check_req);
6508 curproxy->check_len = defproxy.check_len;
6509
6510 if (defproxy.cookie_name)
6511 curproxy->cookie_name = strdup(defproxy.cookie_name);
6512 curproxy->cookie_len = defproxy.cookie_len;
6513
6514 if (defproxy.capture_name)
6515 curproxy->capture_name = strdup(defproxy.capture_name);
6516 curproxy->capture_namelen = defproxy.capture_namelen;
6517 curproxy->capture_len = defproxy.capture_len;
6518
6519 if (defproxy.errmsg.msg400)
6520 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6521 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6522
6523 if (defproxy.errmsg.msg403)
6524 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6525 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6526
6527 if (defproxy.errmsg.msg408)
6528 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6529 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6530
6531 if (defproxy.errmsg.msg500)
6532 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6533 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6534
6535 if (defproxy.errmsg.msg502)
6536 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6537 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6538
6539 if (defproxy.errmsg.msg503)
6540 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6541 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6542
6543 if (defproxy.errmsg.msg504)
6544 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6545 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6546
willy tarreaua41a8b42005-12-17 14:02:24 +01006547 curproxy->clitimeout = defproxy.clitimeout;
6548 curproxy->contimeout = defproxy.contimeout;
6549 curproxy->srvtimeout = defproxy.srvtimeout;
6550 curproxy->mode = defproxy.mode;
6551 curproxy->logfac1 = defproxy.logfac1;
6552 curproxy->logsrv1 = defproxy.logsrv1;
6553 curproxy->loglev1 = defproxy.loglev1;
6554 curproxy->logfac2 = defproxy.logfac2;
6555 curproxy->logsrv2 = defproxy.logsrv2;
6556 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006557 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006558 curproxy->grace = defproxy.grace;
6559 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006560 curproxy->mon_net = defproxy.mon_net;
6561 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006562 return 0;
6563 }
6564 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006565 /* some variables may have already been initialized earlier */
6566 if (defproxy.check_req) free(defproxy.check_req);
6567 if (defproxy.cookie_name) free(defproxy.cookie_name);
6568 if (defproxy.capture_name) free(defproxy.capture_name);
6569 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6570 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6571 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6572 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6573 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6574 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6575 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6576
6577 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006578 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006579 return 0;
6580 }
6581 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006582 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006583 return -1;
6584 }
6585
willy tarreaua41a8b42005-12-17 14:02:24 +01006586 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6587 if (curproxy == &defproxy) {
6588 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6589 return -1;
6590 }
6591
6592 if (strchr(args[1], ':') == NULL) {
6593 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6594 file, linenum, args[0]);
6595 return -1;
6596 }
6597 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006598 if (!curproxy->listen)
6599 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006600 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006601 return 0;
6602 }
willy tarreaub1285d52005-12-18 01:20:14 +01006603 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6604 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6605 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6606 file, linenum, args[0]);
6607 return -1;
6608 }
6609 /* flush useless bits */
6610 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6611 return 0;
6612 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006613 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006614 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6615 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6616 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6617 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006618 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006619 return -1;
6620 }
6621 }
6622 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006623 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006624 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006625 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6626 curproxy->state = PR_STNEW;
6627 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006628 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6629 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006630// if (curproxy == &defproxy) {
6631// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6632// return -1;
6633// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006634
willy tarreau9fe663a2005-12-17 13:02:59 +01006635 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006636// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6637// file, linenum);
6638// return 0;
6639 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006640 }
6641
6642 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006643 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6644 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006645 return -1;
6646 }
6647 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006648 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006649
6650 cur_arg = 2;
6651 while (*(args[cur_arg])) {
6652 if (!strcmp(args[cur_arg], "rewrite")) {
6653 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006654 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006655 else if (!strcmp(args[cur_arg], "indirect")) {
6656 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006657 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006658 else if (!strcmp(args[cur_arg], "insert")) {
6659 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006660 }
willy tarreau240afa62005-12-17 13:14:35 +01006661 else if (!strcmp(args[cur_arg], "nocache")) {
6662 curproxy->options |= PR_O_COOK_NOC;
6663 }
willy tarreaucd878942005-12-17 13:27:43 +01006664 else if (!strcmp(args[cur_arg], "postonly")) {
6665 curproxy->options |= PR_O_COOK_POST;
6666 }
willy tarreau0174f312005-12-18 01:02:42 +01006667 else if (!strcmp(args[cur_arg], "prefix")) {
6668 curproxy->options |= PR_O_COOK_PFX;
6669 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006670 else {
willy tarreau0174f312005-12-18 01:02:42 +01006671 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006672 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006673 return -1;
6674 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006675 cur_arg++;
6676 }
willy tarreau0174f312005-12-18 01:02:42 +01006677 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6678 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6679 file, linenum);
6680 return -1;
6681 }
6682
6683 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6684 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006685 file, linenum);
6686 return -1;
6687 }
willy tarreau12350152005-12-18 01:03:27 +01006688 }/* end else if (!strcmp(args[0], "cookie")) */
6689 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6690// if (curproxy == &defproxy) {
6691// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6692// return -1;
6693// }
6694
6695 if (curproxy->appsession_name != NULL) {
6696// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6697// file, linenum);
6698// return 0;
6699 free(curproxy->appsession_name);
6700 }
6701
6702 if (*(args[5]) == 0) {
6703 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6704 file, linenum, args[0]);
6705 return -1;
6706 }
6707 have_appsession = 1;
6708 curproxy->appsession_name = strdup(args[1]);
6709 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6710 curproxy->appsession_len = atoi(args[3]);
6711 curproxy->appsession_timeout = atoi(args[5]);
6712 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6713 if (rc) {
6714 Alert("Error Init Appsession Hashtable.\n");
6715 return -1;
6716 }
6717 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006718 else if (!strcmp(args[0], "capture")) {
6719 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6720 // if (curproxy == &defproxy) {
6721 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6722 // return -1;
6723 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006724
willy tarreau4302f492005-12-18 01:00:37 +01006725 if (curproxy->capture_name != NULL) {
6726 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6727 // file, linenum, args[0]);
6728 // return 0;
6729 free(curproxy->capture_name);
6730 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006731
willy tarreau4302f492005-12-18 01:00:37 +01006732 if (*(args[4]) == 0) {
6733 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6734 file, linenum, args[0]);
6735 return -1;
6736 }
6737 curproxy->capture_name = strdup(args[2]);
6738 curproxy->capture_namelen = strlen(curproxy->capture_name);
6739 curproxy->capture_len = atol(args[4]);
6740 if (curproxy->capture_len >= CAPTURE_LEN) {
6741 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6742 file, linenum, CAPTURE_LEN - 1);
6743 curproxy->capture_len = CAPTURE_LEN - 1;
6744 }
6745 curproxy->to_log |= LW_COOKIE;
6746 }
6747 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6748 struct cap_hdr *hdr;
6749
6750 if (curproxy == &defproxy) {
6751 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6752 return -1;
6753 }
6754
6755 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6756 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6757 file, linenum, args[0], args[1]);
6758 return -1;
6759 }
6760
6761 hdr = calloc(sizeof(struct cap_hdr), 1);
6762 hdr->next = curproxy->req_cap;
6763 hdr->name = strdup(args[3]);
6764 hdr->namelen = strlen(args[3]);
6765 hdr->len = atol(args[5]);
6766 hdr->index = curproxy->nb_req_cap++;
6767 curproxy->req_cap = hdr;
6768 curproxy->to_log |= LW_REQHDR;
6769 }
6770 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6771 struct cap_hdr *hdr;
6772
6773 if (curproxy == &defproxy) {
6774 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6775 return -1;
6776 }
6777
6778 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6779 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6780 file, linenum, args[0], args[1]);
6781 return -1;
6782 }
6783 hdr = calloc(sizeof(struct cap_hdr), 1);
6784 hdr->next = curproxy->rsp_cap;
6785 hdr->name = strdup(args[3]);
6786 hdr->namelen = strlen(args[3]);
6787 hdr->len = atol(args[5]);
6788 hdr->index = curproxy->nb_rsp_cap++;
6789 curproxy->rsp_cap = hdr;
6790 curproxy->to_log |= LW_RSPHDR;
6791 }
6792 else {
6793 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006794 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006795 return -1;
6796 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006797 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006798 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006799 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006800 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006801 return 0;
6802 }
6803 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006804 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6805 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006806 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006807 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006808 curproxy->contimeout = atol(args[1]);
6809 }
6810 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006811 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006812 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6813 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006814 return 0;
6815 }
6816 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006817 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6818 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006819 return -1;
6820 }
6821 curproxy->clitimeout = atol(args[1]);
6822 }
6823 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006824 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006825 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006826 return 0;
6827 }
6828 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006829 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6830 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006831 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006832 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006833 curproxy->srvtimeout = atol(args[1]);
6834 }
6835 else if (!strcmp(args[0], "retries")) { /* connection retries */
6836 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006837 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6838 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006839 return -1;
6840 }
6841 curproxy->conn_retries = atol(args[1]);
6842 }
6843 else if (!strcmp(args[0], "option")) {
6844 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006845 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006846 return -1;
6847 }
6848 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006849 /* enable reconnections to dispatch */
6850 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006851#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006852 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006853 /* enable transparent proxy connections */
6854 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006855#endif
6856 else if (!strcmp(args[1], "keepalive"))
6857 /* enable keep-alive */
6858 curproxy->options |= PR_O_KEEPALIVE;
6859 else if (!strcmp(args[1], "forwardfor"))
6860 /* insert x-forwarded-for field */
6861 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006862 else if (!strcmp(args[1], "logasap"))
6863 /* log as soon as possible, without waiting for the session to complete */
6864 curproxy->options |= PR_O_LOGASAP;
6865 else if (!strcmp(args[1], "httpclose"))
6866 /* force connection: close in both directions in HTTP mode */
6867 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01006868 else if (!strcmp(args[1], "forceclose"))
6869 /* force connection: close in both directions in HTTP mode and enforce end of session */
6870 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006871 else if (!strcmp(args[1], "checkcache"))
6872 /* require examination of cacheability of the 'set-cookie' field */
6873 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006874 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006875 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006876 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006877 else if (!strcmp(args[1], "tcplog"))
6878 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006879 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006880 else if (!strcmp(args[1], "dontlognull")) {
6881 /* don't log empty requests */
6882 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006883 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006884 else if (!strcmp(args[1], "tcpka")) {
6885 /* enable TCP keep-alives on client and server sessions */
6886 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6887 }
6888 else if (!strcmp(args[1], "clitcpka")) {
6889 /* enable TCP keep-alives on client sessions */
6890 curproxy->options |= PR_O_TCP_CLI_KA;
6891 }
6892 else if (!strcmp(args[1], "srvtcpka")) {
6893 /* enable TCP keep-alives on server sessions */
6894 curproxy->options |= PR_O_TCP_SRV_KA;
6895 }
Willy TARREAU3481c462006-03-01 22:37:57 +01006896 else if (!strcmp(args[1], "allbackups")) {
6897 /* Use all backup servers simultaneously */
6898 curproxy->options |= PR_O_USE_ALL_BK;
6899 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006900 else if (!strcmp(args[1], "httpchk")) {
6901 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006902 if (curproxy->check_req != NULL) {
6903 free(curproxy->check_req);
6904 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006905 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006906 if (!*args[2]) { /* no argument */
6907 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6908 curproxy->check_len = strlen(DEF_CHECK_REQ);
6909 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006910 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6911 curproxy->check_req = (char *)malloc(reqlen);
6912 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6913 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006914 } else { /* more arguments : METHOD URI [HTTP_VER] */
6915 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6916 if (*args[4])
6917 reqlen += strlen(args[4]);
6918 else
6919 reqlen += strlen("HTTP/1.0");
6920
6921 curproxy->check_req = (char *)malloc(reqlen);
6922 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6923 "%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 +01006924 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006925 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006926 else if (!strcmp(args[1], "persist")) {
6927 /* persist on using the server specified by the cookie, even when it's down */
6928 curproxy->options |= PR_O_PERSIST;
6929 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006930 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006931 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006932 return -1;
6933 }
6934 return 0;
6935 }
6936 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6937 /* enable reconnections to dispatch */
6938 curproxy->options |= PR_O_REDISP;
6939 }
willy tarreaua1598082005-12-17 13:08:06 +01006940#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006941 else if (!strcmp(args[0], "transparent")) {
6942 /* enable transparent proxy connections */
6943 curproxy->options |= PR_O_TRANSP;
6944 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006945#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006946 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6947 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006948 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006949 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006950 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006951 curproxy->maxconn = atol(args[1]);
6952 }
6953 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6954 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006955 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\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->grace = atol(args[1]);
6959 }
6960 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006961 if (curproxy == &defproxy) {
6962 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6963 return -1;
6964 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006965 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006966 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006967 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006968 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006969 curproxy->dispatch_addr = *str2sa(args[1]);
6970 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006971 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006972 if (*(args[1])) {
6973 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006974 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006975 }
willy tarreau1a3442d2006-03-24 21:03:20 +01006976 else if (!strcmp(args[1], "source")) {
6977 curproxy->options |= PR_O_BALANCE_SH;
6978 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006979 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01006980 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006981 return -1;
6982 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006983 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006984 else /* if no option is set, use round-robin by default */
6985 curproxy->options |= PR_O_BALANCE_RR;
6986 }
6987 else if (!strcmp(args[0], "server")) { /* server address */
6988 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006989 char *rport;
6990 char *raddr;
6991 short realport;
6992 int do_check;
6993
6994 if (curproxy == &defproxy) {
6995 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6996 return -1;
6997 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006998
willy tarreaua41a8b42005-12-17 14:02:24 +01006999 if (!*args[2]) {
7000 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007001 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007002 return -1;
7003 }
7004 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
7005 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7006 return -1;
7007 }
willy tarreau0174f312005-12-18 01:02:42 +01007008
7009 if (curproxy->srv == NULL)
7010 curproxy->srv = newsrv;
7011 else
7012 curproxy->cursrv->next = newsrv;
7013 curproxy->cursrv = newsrv;
7014
7015 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01007016 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007017
7018 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01007019 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01007020 newsrv->id = strdup(args[1]);
7021
7022 /* several ways to check the port component :
7023 * - IP => port=+0, relative
7024 * - IP: => port=+0, relative
7025 * - IP:N => port=N, absolute
7026 * - IP:+N => port=+N, relative
7027 * - IP:-N => port=-N, relative
7028 */
7029 raddr = strdup(args[2]);
7030 rport = strchr(raddr, ':');
7031 if (rport) {
7032 *rport++ = 0;
7033 realport = atol(rport);
7034 if (!isdigit((int)*rport))
7035 newsrv->state |= SRV_MAPPORTS;
7036 } else {
7037 realport = 0;
7038 newsrv->state |= SRV_MAPPORTS;
7039 }
7040
7041 newsrv->addr = *str2sa(raddr);
7042 newsrv->addr.sin_port = htons(realport);
7043 free(raddr);
7044
willy tarreau9fe663a2005-12-17 13:02:59 +01007045 newsrv->curfd = -1; /* no health-check in progress */
7046 newsrv->inter = DEF_CHKINTR;
7047 newsrv->rise = DEF_RISETIME;
7048 newsrv->fall = DEF_FALLTIME;
7049 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7050 cur_arg = 3;
7051 while (*args[cur_arg]) {
7052 if (!strcmp(args[cur_arg], "cookie")) {
7053 newsrv->cookie = strdup(args[cur_arg + 1]);
7054 newsrv->cklen = strlen(args[cur_arg + 1]);
7055 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007056 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007057 else if (!strcmp(args[cur_arg], "rise")) {
7058 newsrv->rise = atol(args[cur_arg + 1]);
7059 newsrv->health = newsrv->rise;
7060 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007061 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007062 else if (!strcmp(args[cur_arg], "fall")) {
7063 newsrv->fall = atol(args[cur_arg + 1]);
7064 cur_arg += 2;
7065 }
7066 else if (!strcmp(args[cur_arg], "inter")) {
7067 newsrv->inter = atol(args[cur_arg + 1]);
7068 cur_arg += 2;
7069 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007070 else if (!strcmp(args[cur_arg], "port")) {
7071 newsrv->check_port = atol(args[cur_arg + 1]);
7072 cur_arg += 2;
7073 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007074 else if (!strcmp(args[cur_arg], "backup")) {
7075 newsrv->state |= SRV_BACKUP;
7076 cur_arg ++;
7077 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007078 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007079 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007080 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007081 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007082 }
willy tarreau0174f312005-12-18 01:02:42 +01007083 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7084 if (!*args[cur_arg + 1]) {
7085 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7086 file, linenum, "source");
7087 return -1;
7088 }
7089 newsrv->state |= SRV_BIND_SRC;
7090 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7091 cur_arg += 2;
7092 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007093 else {
willy tarreau0174f312005-12-18 01:02:42 +01007094 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 +01007095 file, linenum, newsrv->id);
7096 return -1;
7097 }
7098 }
7099
7100 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007101 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7102 newsrv->check_port = realport; /* by default */
7103 if (!newsrv->check_port) {
7104 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 +01007105 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007106 return -1;
7107 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007108 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007109 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007110
willy tarreau62084d42006-03-24 18:57:41 +01007111 if (newsrv->state & SRV_BACKUP)
7112 curproxy->srv_bck++;
7113 else
7114 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007115 }
7116 else if (!strcmp(args[0], "log")) { /* syslog server address */
7117 struct sockaddr_in *sa;
7118 int facility;
7119
7120 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7121 curproxy->logfac1 = global.logfac1;
7122 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007123 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007124 curproxy->logfac2 = global.logfac2;
7125 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007126 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007127 }
7128 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007129 int level;
7130
willy tarreau0f7af912005-12-17 12:21:26 +01007131 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7132 if (!strcmp(log_facilities[facility], args[2]))
7133 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007134
willy tarreau0f7af912005-12-17 12:21:26 +01007135 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007136 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007137 exit(1);
7138 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007139
willy tarreau8337c6b2005-12-17 13:41:01 +01007140 level = 7; /* max syslog level = debug */
7141 if (*(args[3])) {
7142 while (level >= 0 && strcmp(log_levels[level], args[3]))
7143 level--;
7144 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007145 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007146 exit(1);
7147 }
7148 }
7149
willy tarreau0f7af912005-12-17 12:21:26 +01007150 sa = str2sa(args[1]);
7151 if (!sa->sin_port)
7152 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007153
willy tarreau0f7af912005-12-17 12:21:26 +01007154 if (curproxy->logfac1 == -1) {
7155 curproxy->logsrv1 = *sa;
7156 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007157 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007158 }
7159 else if (curproxy->logfac2 == -1) {
7160 curproxy->logsrv2 = *sa;
7161 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007162 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007163 }
7164 else {
7165 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007166 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007167 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007168 }
7169 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007170 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007171 file, linenum);
7172 return -1;
7173 }
7174 }
willy tarreaua1598082005-12-17 13:08:06 +01007175 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007176 if (!*args[1]) {
7177 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007178 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007179 return -1;
7180 }
7181
7182 curproxy->source_addr = *str2sa(args[1]);
7183 curproxy->options |= PR_O_BIND_SRC;
7184 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007185 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7186 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007187 if (curproxy == &defproxy) {
7188 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7189 return -1;
7190 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007191
7192 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007193 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7194 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007195 return -1;
7196 }
7197
7198 preg = calloc(1, sizeof(regex_t));
7199 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007200 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007201 return -1;
7202 }
7203
willy tarreauc1f47532005-12-18 01:08:26 +01007204 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7205 if (err) {
7206 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7207 file, linenum, *err);
7208 return -1;
7209 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007210 }
7211 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7212 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007213 if (curproxy == &defproxy) {
7214 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7215 return -1;
7216 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007217
7218 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007219 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007220 return -1;
7221 }
7222
7223 preg = calloc(1, sizeof(regex_t));
7224 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007225 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007226 return -1;
7227 }
7228
7229 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7230 }
7231 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7232 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007233 if (curproxy == &defproxy) {
7234 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7235 return -1;
7236 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007237
7238 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007239 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007240 return -1;
7241 }
7242
7243 preg = calloc(1, sizeof(regex_t));
7244 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007245 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007246 return -1;
7247 }
7248
7249 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7250 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007251 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7252 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007253 if (curproxy == &defproxy) {
7254 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7255 return -1;
7256 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007257
7258 if (*(args[1]) == 0) {
7259 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7260 return -1;
7261 }
7262
7263 preg = calloc(1, sizeof(regex_t));
7264 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7265 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7266 return -1;
7267 }
7268
7269 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7270 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007271 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7272 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007273 if (curproxy == &defproxy) {
7274 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7275 return -1;
7276 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007277
7278 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007279 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007280 return -1;
7281 }
7282
7283 preg = calloc(1, sizeof(regex_t));
7284 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007285 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007286 return -1;
7287 }
7288
7289 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7290 }
7291 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7292 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007293 if (curproxy == &defproxy) {
7294 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7295 return -1;
7296 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007297
7298 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007299 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7300 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007301 return -1;
7302 }
7303
7304 preg = calloc(1, sizeof(regex_t));
7305 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007306 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007307 return -1;
7308 }
7309
willy tarreauc1f47532005-12-18 01:08:26 +01007310 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7311 if (err) {
7312 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7313 file, linenum, *err);
7314 return -1;
7315 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007316 }
7317 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7318 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007319 if (curproxy == &defproxy) {
7320 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7321 return -1;
7322 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007323
7324 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007325 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007326 return -1;
7327 }
7328
7329 preg = calloc(1, sizeof(regex_t));
7330 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007331 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007332 return -1;
7333 }
7334
7335 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7336 }
7337 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7338 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007339 if (curproxy == &defproxy) {
7340 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7341 return -1;
7342 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007343
7344 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007345 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007346 return -1;
7347 }
7348
7349 preg = calloc(1, sizeof(regex_t));
7350 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007351 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007352 return -1;
7353 }
7354
7355 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7356 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007357 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7358 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007359 if (curproxy == &defproxy) {
7360 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7361 return -1;
7362 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007363
7364 if (*(args[1]) == 0) {
7365 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7366 return -1;
7367 }
7368
7369 preg = calloc(1, sizeof(regex_t));
7370 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7371 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7372 return -1;
7373 }
7374
7375 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7376 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007377 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7378 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007379 if (curproxy == &defproxy) {
7380 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7381 return -1;
7382 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007383
7384 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007385 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007386 return -1;
7387 }
7388
7389 preg = calloc(1, sizeof(regex_t));
7390 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007391 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007392 return -1;
7393 }
7394
7395 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7396 }
7397 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007398 if (curproxy == &defproxy) {
7399 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7400 return -1;
7401 }
7402
willy tarreau9fe663a2005-12-17 13:02:59 +01007403 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007404 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007405 return 0;
7406 }
7407
7408 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007409 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007410 return -1;
7411 }
7412
willy tarreau4302f492005-12-18 01:00:37 +01007413 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7414 }
7415 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7416 regex_t *preg;
7417
7418 if (*(args[1]) == 0 || *(args[2]) == 0) {
7419 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7420 file, linenum, args[0]);
7421 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007422 }
willy tarreau4302f492005-12-18 01:00:37 +01007423
7424 preg = calloc(1, sizeof(regex_t));
7425 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7426 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7427 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007428 }
willy tarreau4302f492005-12-18 01:00:37 +01007429
willy tarreauc1f47532005-12-18 01:08:26 +01007430 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7431 if (err) {
7432 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7433 file, linenum, *err);
7434 return -1;
7435 }
willy tarreau4302f492005-12-18 01:00:37 +01007436 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007437 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7438 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007439 if (curproxy == &defproxy) {
7440 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7441 return -1;
7442 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007443
7444 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007445 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007446 return -1;
7447 }
willy tarreaue39cd132005-12-17 13:00:18 +01007448
willy tarreau9fe663a2005-12-17 13:02:59 +01007449 preg = calloc(1, sizeof(regex_t));
7450 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007451 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007452 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007453 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007454
willy tarreauc1f47532005-12-18 01:08:26 +01007455 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7456 if (err) {
7457 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7458 file, linenum, *err);
7459 return -1;
7460 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007461 }
willy tarreau982249e2005-12-18 00:57:06 +01007462 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7463 regex_t *preg;
7464 if (curproxy == &defproxy) {
7465 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7466 return -1;
7467 }
7468
7469 if (*(args[1]) == 0) {
7470 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7471 return -1;
7472 }
7473
7474 preg = calloc(1, sizeof(regex_t));
7475 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7476 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7477 return -1;
7478 }
7479
willy tarreauc1f47532005-12-18 01:08:26 +01007480 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7481 if (err) {
7482 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7483 file, linenum, *err);
7484 return -1;
7485 }
willy tarreau982249e2005-12-18 00:57:06 +01007486 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007487 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007488 regex_t *preg;
7489 if (curproxy == &defproxy) {
7490 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7491 return -1;
7492 }
willy tarreaue39cd132005-12-17 13:00:18 +01007493
willy tarreaua41a8b42005-12-17 14:02:24 +01007494 if (*(args[1]) == 0 || *(args[2]) == 0) {
7495 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7496 file, linenum, args[0]);
7497 return -1;
7498 }
willy tarreaue39cd132005-12-17 13:00:18 +01007499
willy tarreaua41a8b42005-12-17 14:02:24 +01007500 preg = calloc(1, sizeof(regex_t));
7501 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7502 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7503 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007504 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007505
willy tarreauc1f47532005-12-18 01:08:26 +01007506 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7507 if (err) {
7508 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7509 file, linenum, *err);
7510 return -1;
7511 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007512 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007513 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7514 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007515 if (curproxy == &defproxy) {
7516 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7517 return -1;
7518 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007519
7520 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007521 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007522 return -1;
7523 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007524
willy tarreau9fe663a2005-12-17 13:02:59 +01007525 preg = calloc(1, sizeof(regex_t));
7526 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007527 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007528 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007529 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007530
willy tarreauc1f47532005-12-18 01:08:26 +01007531 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7532 if (err) {
7533 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7534 file, linenum, *err);
7535 return -1;
7536 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007537 }
willy tarreau982249e2005-12-18 00:57:06 +01007538 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7539 regex_t *preg;
7540 if (curproxy == &defproxy) {
7541 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7542 return -1;
7543 }
7544
7545 if (*(args[1]) == 0) {
7546 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7547 return -1;
7548 }
7549
7550 preg = calloc(1, sizeof(regex_t));
7551 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7552 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7553 return -1;
7554 }
7555
willy tarreauc1f47532005-12-18 01:08:26 +01007556 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7557 if (err) {
7558 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7559 file, linenum, *err);
7560 return -1;
7561 }
willy tarreau982249e2005-12-18 00:57:06 +01007562 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007563 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007564 if (curproxy == &defproxy) {
7565 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7566 return -1;
7567 }
7568
willy tarreau9fe663a2005-12-17 13:02:59 +01007569 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007570 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007571 return 0;
7572 }
7573
7574 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007575 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007576 return -1;
7577 }
7578
7579 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7580 }
willy tarreauc1f47532005-12-18 01:08:26 +01007581 else if (!strcmp(args[0], "errorloc") ||
7582 !strcmp(args[0], "errorloc302") ||
7583 !strcmp(args[0], "errorloc303")) { /* error location */
7584 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007585 char *err;
7586
willy tarreaueedaa9f2005-12-17 14:08:03 +01007587 // if (curproxy == &defproxy) {
7588 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7589 // return -1;
7590 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007591
willy tarreau8337c6b2005-12-17 13:41:01 +01007592 if (*(args[2]) == 0) {
7593 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7594 return -1;
7595 }
7596
7597 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007598 if (!strcmp(args[0], "errorloc303")) {
7599 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7600 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7601 } else {
7602 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7603 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7604 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007605
7606 if (errnum == 400) {
7607 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007608 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007609 free(curproxy->errmsg.msg400);
7610 }
7611 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007612 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007613 }
7614 else if (errnum == 403) {
7615 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007616 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007617 free(curproxy->errmsg.msg403);
7618 }
7619 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007620 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007621 }
7622 else if (errnum == 408) {
7623 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007624 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007625 free(curproxy->errmsg.msg408);
7626 }
7627 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007628 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007629 }
7630 else if (errnum == 500) {
7631 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007632 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007633 free(curproxy->errmsg.msg500);
7634 }
7635 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007636 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007637 }
7638 else if (errnum == 502) {
7639 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007640 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007641 free(curproxy->errmsg.msg502);
7642 }
7643 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007644 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007645 }
7646 else if (errnum == 503) {
7647 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007648 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007649 free(curproxy->errmsg.msg503);
7650 }
7651 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007652 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007653 }
7654 else if (errnum == 504) {
7655 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007656 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007657 free(curproxy->errmsg.msg504);
7658 }
7659 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007660 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007661 }
7662 else {
7663 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7664 free(err);
7665 }
7666 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007667 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007668 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007669 return -1;
7670 }
7671 return 0;
7672}
willy tarreaue39cd132005-12-17 13:00:18 +01007673
willy tarreau5cbea6f2005-12-17 12:48:26 +01007674
willy tarreau9fe663a2005-12-17 13:02:59 +01007675/*
7676 * This function reads and parses the configuration file given in the argument.
7677 * returns 0 if OK, -1 if error.
7678 */
7679int readcfgfile(char *file) {
7680 char thisline[256];
7681 char *line;
7682 FILE *f;
7683 int linenum = 0;
7684 char *end;
7685 char *args[MAX_LINE_ARGS];
7686 int arg;
7687 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007688 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007689 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007690
willy tarreau9fe663a2005-12-17 13:02:59 +01007691 struct proxy *curproxy = NULL;
7692 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007693
willy tarreau9fe663a2005-12-17 13:02:59 +01007694 if ((f=fopen(file,"r")) == NULL)
7695 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007696
willy tarreaueedaa9f2005-12-17 14:08:03 +01007697 init_default_instance();
7698
willy tarreau9fe663a2005-12-17 13:02:59 +01007699 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7700 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007701
willy tarreau9fe663a2005-12-17 13:02:59 +01007702 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007703
willy tarreau9fe663a2005-12-17 13:02:59 +01007704 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007705 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007706 line++;
7707
7708 arg = 0;
7709 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007710
willy tarreau9fe663a2005-12-17 13:02:59 +01007711 while (*line && arg < MAX_LINE_ARGS) {
7712 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7713 * C equivalent value. Other combinations left unchanged (eg: \1).
7714 */
7715 if (*line == '\\') {
7716 int skip = 0;
7717 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7718 *line = line[1];
7719 skip = 1;
7720 }
7721 else if (line[1] == 'r') {
7722 *line = '\r';
7723 skip = 1;
7724 }
7725 else if (line[1] == 'n') {
7726 *line = '\n';
7727 skip = 1;
7728 }
7729 else if (line[1] == 't') {
7730 *line = '\t';
7731 skip = 1;
7732 }
willy tarreauc1f47532005-12-18 01:08:26 +01007733 else if (line[1] == 'x') {
7734 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7735 unsigned char hex1, hex2;
7736 hex1 = toupper(line[2]) - '0';
7737 hex2 = toupper(line[3]) - '0';
7738 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7739 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7740 *line = (hex1<<4) + hex2;
7741 skip = 3;
7742 }
7743 else {
7744 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7745 return -1;
7746 }
7747 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007748 if (skip) {
7749 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7750 end -= skip;
7751 }
7752 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007753 }
willy tarreaua1598082005-12-17 13:08:06 +01007754 else if (*line == '#' || *line == '\n' || *line == '\r') {
7755 /* end of string, end of loop */
7756 *line = 0;
7757 break;
7758 }
willy tarreauc29948c2005-12-17 13:10:27 +01007759 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007760 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007761 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007762 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007763 line++;
7764 args[++arg] = line;
7765 }
7766 else {
7767 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007768 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007769 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007770
willy tarreau9fe663a2005-12-17 13:02:59 +01007771 /* empty line */
7772 if (!**args)
7773 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007774
willy tarreau9fe663a2005-12-17 13:02:59 +01007775 /* zero out remaining args */
7776 while (++arg < MAX_LINE_ARGS) {
7777 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007778 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007779
willy tarreaua41a8b42005-12-17 14:02:24 +01007780 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007781 confsect = CFG_LISTEN;
7782 else if (!strcmp(args[0], "global")) /* global config */
7783 confsect = CFG_GLOBAL;
7784 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007785
willy tarreau9fe663a2005-12-17 13:02:59 +01007786 switch (confsect) {
7787 case CFG_LISTEN:
7788 if (cfg_parse_listen(file, linenum, args) < 0)
7789 return -1;
7790 break;
7791 case CFG_GLOBAL:
7792 if (cfg_parse_global(file, linenum, args) < 0)
7793 return -1;
7794 break;
7795 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007796 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007797 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007798 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007799
7800
willy tarreau0f7af912005-12-17 12:21:26 +01007801 }
7802 fclose(f);
7803
7804 /*
7805 * Now, check for the integrity of all that we have collected.
7806 */
7807
Willy TARREAU3759f982006-03-01 22:44:17 +01007808 /* will be needed further to delay some tasks */
7809 tv_now(&now);
7810
willy tarreau0f7af912005-12-17 12:21:26 +01007811 if ((curproxy = proxy) == NULL) {
7812 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7813 file);
7814 return -1;
7815 }
7816
7817 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007818 curproxy->cursrv = NULL;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007819 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007820 curproxy = curproxy->next;
7821 continue;
7822 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007823
7824 if (curproxy->listen == NULL) {
7825 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);
7826 cfgerr++;
7827 }
7828 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007829 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007830 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007831 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7832 file, curproxy->id);
7833 cfgerr++;
7834 }
7835 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7836 if (curproxy->options & PR_O_TRANSP) {
7837 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7838 file, curproxy->id);
7839 cfgerr++;
7840 }
7841 else if (curproxy->srv == NULL) {
7842 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7843 file, curproxy->id);
7844 cfgerr++;
7845 }
willy tarreaua1598082005-12-17 13:08:06 +01007846 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007847 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7848 file, curproxy->id);
7849 }
7850 }
7851 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007852 if (curproxy->cookie_name != NULL) {
7853 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7854 file, curproxy->id);
7855 }
7856 if ((newsrv = curproxy->srv) != NULL) {
7857 Warning("parsing %s : servers will be ignored for listener %s.\n",
7858 file, curproxy->id);
7859 }
willy tarreaue39cd132005-12-17 13:00:18 +01007860 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007861 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7862 file, curproxy->id);
7863 }
willy tarreaue39cd132005-12-17 13:00:18 +01007864 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007865 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7866 file, curproxy->id);
7867 }
7868 }
7869 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7870 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7871 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7872 file, curproxy->id);
7873 cfgerr++;
7874 }
7875 else {
7876 while (newsrv != NULL) {
7877 /* nothing to check for now */
7878 newsrv = newsrv->next;
7879 }
7880 }
7881 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007882
7883 if (curproxy->options & PR_O_LOGASAP)
7884 curproxy->to_log &= ~LW_BYTES;
7885
willy tarreau8337c6b2005-12-17 13:41:01 +01007886 if (curproxy->errmsg.msg400 == NULL) {
7887 curproxy->errmsg.msg400 = (char *)HTTP_400;
7888 curproxy->errmsg.len400 = strlen(HTTP_400);
7889 }
7890 if (curproxy->errmsg.msg403 == NULL) {
7891 curproxy->errmsg.msg403 = (char *)HTTP_403;
7892 curproxy->errmsg.len403 = strlen(HTTP_403);
7893 }
7894 if (curproxy->errmsg.msg408 == NULL) {
7895 curproxy->errmsg.msg408 = (char *)HTTP_408;
7896 curproxy->errmsg.len408 = strlen(HTTP_408);
7897 }
7898 if (curproxy->errmsg.msg500 == NULL) {
7899 curproxy->errmsg.msg500 = (char *)HTTP_500;
7900 curproxy->errmsg.len500 = strlen(HTTP_500);
7901 }
7902 if (curproxy->errmsg.msg502 == NULL) {
7903 curproxy->errmsg.msg502 = (char *)HTTP_502;
7904 curproxy->errmsg.len502 = strlen(HTTP_502);
7905 }
7906 if (curproxy->errmsg.msg503 == NULL) {
7907 curproxy->errmsg.msg503 = (char *)HTTP_503;
7908 curproxy->errmsg.len503 = strlen(HTTP_503);
7909 }
7910 if (curproxy->errmsg.msg504 == NULL) {
7911 curproxy->errmsg.msg504 = (char *)HTTP_504;
7912 curproxy->errmsg.len504 = strlen(HTTP_504);
7913 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007914
7915 /* now we'll start this proxy's health checks if any */
7916 /* 1- count the checkers to run simultaneously */
7917 nbchk = 0;
7918 mininter = 0;
7919 newsrv = curproxy->srv;
7920 while (newsrv != NULL) {
7921 if (newsrv->state & SRV_CHECKED) {
7922 if (!mininter || mininter > newsrv->inter)
7923 mininter = newsrv->inter;
7924 nbchk++;
7925 }
7926 newsrv = newsrv->next;
7927 }
7928
7929 /* 2- start them as far as possible from each others while respecting
7930 * their own intervals. For this, we will start them after their own
7931 * interval added to the min interval divided by the number of servers,
7932 * weighted by the server's position in the list.
7933 */
7934 if (nbchk > 0) {
7935 struct task *t;
7936 int srvpos;
7937
7938 newsrv = curproxy->srv;
7939 srvpos = 0;
7940 while (newsrv != NULL) {
7941 /* should this server be checked ? */
7942 if (newsrv->state & SRV_CHECKED) {
7943 if ((t = pool_alloc(task)) == NULL) {
7944 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7945 return -1;
7946 }
7947
7948 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
7949 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
7950 t->state = TASK_IDLE;
7951 t->process = process_chk;
7952 t->context = newsrv;
7953
7954 /* check this every ms */
7955 tv_delayfrom(&t->expire, &now,
7956 newsrv->inter + mininter * srvpos / nbchk);
7957 task_queue(t);
7958 //task_wakeup(&rq, t);
7959 srvpos++;
7960 }
7961 newsrv = newsrv->next;
7962 }
7963 }
7964
willy tarreau0f7af912005-12-17 12:21:26 +01007965 curproxy = curproxy->next;
7966 }
7967 if (cfgerr > 0) {
7968 Alert("Errors found in configuration file, aborting.\n");
7969 return -1;
7970 }
7971 else
7972 return 0;
7973}
7974
7975
7976/*
7977 * This function initializes all the necessary variables. It only returns
7978 * if everything is OK. If something fails, it exits.
7979 */
7980void init(int argc, char **argv) {
7981 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007982 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007983 char *old_argv = *argv;
7984 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007985 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007986
7987 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007988 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007989 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007990 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007991 exit(1);
7992 }
7993
willy tarreau746e26b2006-03-25 11:14:35 +01007994#ifdef HAPROXY_MEMMAX
7995 global.rlimit_memmax = HAPROXY_MEMMAX;
7996#endif
7997
Willy TARREAUa9e75f62006-03-01 22:27:48 +01007998 /* initialize the libc's localtime structures once for all so that we
7999 * won't be missing memory if we want to send alerts under OOM conditions.
8000 */
8001 tv_now(&now);
8002 localtime(&now.tv_sec);
8003
willy tarreau4302f492005-12-18 01:00:37 +01008004 /* initialize the log header encoding map : '{|}"#' should be encoded with
8005 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
8006 * URL encoding only requires '"', '#' to be encoded as well as non-
8007 * printable characters above.
8008 */
8009 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
8010 memset(url_encode_map, 0, sizeof(url_encode_map));
8011 for (i = 0; i < 32; i++) {
8012 FD_SET(i, hdr_encode_map);
8013 FD_SET(i, url_encode_map);
8014 }
8015 for (i = 127; i < 256; i++) {
8016 FD_SET(i, hdr_encode_map);
8017 FD_SET(i, url_encode_map);
8018 }
8019
8020 tmp = "\"#{|}";
8021 while (*tmp) {
8022 FD_SET(*tmp, hdr_encode_map);
8023 tmp++;
8024 }
8025
8026 tmp = "\"#";
8027 while (*tmp) {
8028 FD_SET(*tmp, url_encode_map);
8029 tmp++;
8030 }
8031
willy tarreau64a3cc32005-12-18 01:13:11 +01008032 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8033#if defined(ENABLE_POLL)
8034 cfg_polling_mechanism |= POLL_USE_POLL;
8035#endif
8036#if defined(ENABLE_EPOLL)
8037 cfg_polling_mechanism |= POLL_USE_EPOLL;
8038#endif
8039
willy tarreau0f7af912005-12-17 12:21:26 +01008040 pid = getpid();
8041 progname = *argv;
8042 while ((tmp = strchr(progname, '/')) != NULL)
8043 progname = tmp + 1;
8044
8045 argc--; argv++;
8046 while (argc > 0) {
8047 char *flag;
8048
8049 if (**argv == '-') {
8050 flag = *argv+1;
8051
8052 /* 1 arg */
8053 if (*flag == 'v') {
8054 display_version();
8055 exit(0);
8056 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008057#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008058 else if (*flag == 'd' && flag[1] == 'e')
8059 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008060#endif
8061#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008062 else if (*flag == 'd' && flag[1] == 'p')
8063 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008064#endif
willy tarreau982249e2005-12-18 00:57:06 +01008065 else if (*flag == 'V')
8066 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008067 else if (*flag == 'd' && flag[1] == 'b')
8068 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008069 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008070 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008071 else if (*flag == 'c')
8072 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008073 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008074 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008075 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008076 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01008077#if STATTIME > 0
8078 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01008079 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01008080 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01008081 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01008082#endif
willy tarreau53e99702006-03-25 18:53:50 +01008083 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8084 /* list of pids to finish ('f') or terminate ('t') */
8085
8086 if (flag[1] == 'f')
8087 oldpids_sig = SIGUSR1; /* finish then exit */
8088 else
8089 oldpids_sig = SIGTERM; /* terminate immediately */
8090 argv++; argc--;
8091
8092 if (argc > 0) {
8093 oldpids = calloc(argc, sizeof(int));
8094 while (argc > 0) {
8095 oldpids[nb_oldpids] = atol(*argv);
8096 if (oldpids[nb_oldpids] <= 0)
8097 usage(old_argv);
8098 argc--; argv++;
8099 nb_oldpids++;
8100 }
8101 }
8102 }
willy tarreau0f7af912005-12-17 12:21:26 +01008103 else { /* >=2 args */
8104 argv++; argc--;
8105 if (argc == 0)
8106 usage(old_argv);
8107
8108 switch (*flag) {
8109 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008110 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008111 case 'N' : cfg_maxpconn = atol(*argv); break;
8112 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008113 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008114 default: usage(old_argv);
8115 }
8116 }
8117 }
8118 else
8119 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008120 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008121 }
8122
willy tarreaud0fb4652005-12-18 01:32:04 +01008123 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008124 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8125 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008126
willy tarreau0f7af912005-12-17 12:21:26 +01008127 if (!cfg_cfgfile)
8128 usage(old_argv);
8129
8130 gethostname(hostname, MAX_HOSTNAME_LEN);
8131
willy tarreau12350152005-12-18 01:03:27 +01008132 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008133 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008134 if (readcfgfile(cfg_cfgfile) < 0) {
8135 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8136 exit(1);
8137 }
willy tarreau12350152005-12-18 01:03:27 +01008138 if (have_appsession)
8139 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008140
willy tarreau982249e2005-12-18 00:57:06 +01008141 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008142 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8143 exit(0);
8144 }
8145
willy tarreau9fe663a2005-12-17 13:02:59 +01008146 if (cfg_maxconn > 0)
8147 global.maxconn = cfg_maxconn;
8148
willy tarreaufe2c5c12005-12-17 14:14:34 +01008149 if (cfg_pidfile) {
8150 if (global.pidfile)
8151 free(global.pidfile);
8152 global.pidfile = strdup(cfg_pidfile);
8153 }
8154
willy tarreau9fe663a2005-12-17 13:02:59 +01008155 if (global.maxconn == 0)
8156 global.maxconn = DEFAULT_MAXCONN;
8157
Willy TARREAU203b0b62006-03-12 18:00:28 +01008158 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008159
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008160 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008161 /* command line debug mode inhibits configuration mode */
8162 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8163 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008164 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8165 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008166
8167 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8168 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8169 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8170 }
8171
8172 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008173 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8174 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008175 global.nbproc = 1;
8176 }
8177
8178 if (global.nbproc < 1)
8179 global.nbproc = 1;
8180
willy tarreau0f7af912005-12-17 12:21:26 +01008181 StaticReadEvent = (fd_set *)calloc(1,
8182 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008183 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008184 StaticWriteEvent = (fd_set *)calloc(1,
8185 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008186 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008187
8188 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008189 sizeof(struct fdtab) * (global.maxsock));
8190 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008191 fdtab[i].state = FD_STCLOSE;
8192 }
8193}
8194
8195/*
willy tarreau41310e72006-03-25 18:17:56 +01008196 * this function starts all the proxies. Its return value is composed from
8197 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8198 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008199 */
willy tarreau41310e72006-03-25 18:17:56 +01008200int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008201 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008202 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008203 int err = ERR_NONE;
8204 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008205
8206 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008207 if (curproxy->state != PR_STNEW)
8208 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01008209
willy tarreau41310e72006-03-25 18:17:56 +01008210 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01008211 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008212 if (listener->fd != -1)
8213 continue; /* already initialized */
8214
8215 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
8216 if (verbose)
8217 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8218 curproxy->id);
8219 err |= ERR_RETRYABLE;
8220 pxerr |= 1;
8221 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008222 }
willy tarreau0f7af912005-12-17 12:21:26 +01008223
willy tarreaua41a8b42005-12-17 14:02:24 +01008224 if (fd >= global.maxsock) {
8225 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. 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 tarreau5cbea6f2005-12-17 12:48:26 +01008232
willy tarreaua41a8b42005-12-17 14:02:24 +01008233 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
8234 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
8235 (char *) &one, sizeof(one)) == -1)) {
8236 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
8237 curproxy->id);
8238 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008239 err |= ERR_FATAL;
8240 pxerr |= 1;
8241 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008242 }
willy tarreau0f7af912005-12-17 12:21:26 +01008243
willy tarreaua41a8b42005-12-17 14:02:24 +01008244 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8245 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8246 curproxy->id);
8247 }
willy tarreau0f7af912005-12-17 12:21:26 +01008248
willy tarreaua41a8b42005-12-17 14:02:24 +01008249 if (bind(fd,
8250 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008251 listener->addr.ss_family == AF_INET6 ?
8252 sizeof(struct sockaddr_in6) :
8253 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008254 if (verbose)
8255 Alert("cannot bind socket for proxy %s. Aborting.\n",
8256 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008257 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008258 err |= ERR_RETRYABLE;
8259 pxerr |= 1;
8260 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008261 }
willy tarreau0f7af912005-12-17 12:21:26 +01008262
willy tarreaua41a8b42005-12-17 14:02:24 +01008263 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008264 if (verbose)
8265 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8266 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008267 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008268 err |= ERR_RETRYABLE;
8269 pxerr |= 1;
8270 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008271 }
willy tarreau0f7af912005-12-17 12:21:26 +01008272
willy tarreau41310e72006-03-25 18:17:56 +01008273 /* the socket is ready */
8274 listener->fd = fd;
8275
willy tarreaua41a8b42005-12-17 14:02:24 +01008276 /* the function for the accept() event */
8277 fdtab[fd].read = &event_accept;
8278 fdtab[fd].write = NULL; /* never called */
8279 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01008280 fdtab[fd].state = FD_STLISTEN;
8281 FD_SET(fd, StaticReadEvent);
8282 fd_insert(fd);
8283 listeners++;
8284 }
willy tarreau41310e72006-03-25 18:17:56 +01008285
8286 if (!pxerr) {
8287 curproxy->state = PR_STRUN;
8288 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
8289 }
willy tarreau0f7af912005-12-17 12:21:26 +01008290 }
willy tarreau41310e72006-03-25 18:17:56 +01008291
8292 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01008293}
8294
willy tarreaub952e1d2005-12-18 01:31:20 +01008295int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008296
8297 appsess *temp1,*temp2;
8298 temp1 = (appsess *)key1;
8299 temp2 = (appsess *)key2;
8300
8301 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8302 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8303
8304 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8305}/* end match_str */
8306
willy tarreaub952e1d2005-12-18 01:31:20 +01008307void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008308 appsess *temp1;
8309
8310 //printf("destroy called\n");
8311 temp1 = (appsess *)data;
8312
8313 if (temp1->sessid)
8314 pool_free_to(apools.sessid, temp1->sessid);
8315
8316 if (temp1->serverid)
8317 pool_free_to(apools.serverid, temp1->serverid);
8318
8319 pool_free(appsess, temp1);
8320} /* end destroy */
8321
8322void appsession_cleanup( void )
8323{
8324 struct proxy *p = proxy;
8325
8326 while(p) {
8327 chtbl_destroy(&(p->htbl_proxy));
8328 p = p->next;
8329 }
8330}/* end appsession_cleanup() */
8331
8332void pool_destroy(void **pool)
8333{
8334 void *temp, *next;
8335 next = pool;
8336 while (next) {
8337 temp = next;
8338 next = *(void **)temp;
8339 free(temp);
8340 }
8341}/* end pool_destroy() */
8342
willy tarreaub952e1d2005-12-18 01:31:20 +01008343void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008344 struct proxy *p = proxy;
8345 struct cap_hdr *h,*h_next;
8346 struct server *s,*s_next;
8347 struct listener *l,*l_next;
8348
8349 while (p) {
8350 if (p->id)
8351 free(p->id);
8352
8353 if (p->check_req)
8354 free(p->check_req);
8355
8356 if (p->cookie_name)
8357 free(p->cookie_name);
8358
8359 if (p->capture_name)
8360 free(p->capture_name);
8361
8362 /* only strup if the user have set in config.
8363 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008364 if (p->errmsg.msg400) free(p->errmsg.msg400);
8365 if (p->errmsg.msg403) free(p->errmsg.msg403);
8366 if (p->errmsg.msg408) free(p->errmsg.msg408);
8367 if (p->errmsg.msg500) free(p->errmsg.msg500);
8368 if (p->errmsg.msg502) free(p->errmsg.msg502);
8369 if (p->errmsg.msg503) free(p->errmsg.msg503);
8370 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008371 */
8372 if (p->appsession_name)
8373 free(p->appsession_name);
8374
8375 h = p->req_cap;
8376 while (h) {
8377 h_next = h->next;
8378 if (h->name)
8379 free(h->name);
8380 pool_destroy(h->pool);
8381 free(h);
8382 h = h_next;
8383 }/* end while(h) */
8384
8385 h = p->rsp_cap;
8386 while (h) {
8387 h_next = h->next;
8388 if (h->name)
8389 free(h->name);
8390
8391 pool_destroy(h->pool);
8392 free(h);
8393 h = h_next;
8394 }/* end while(h) */
8395
8396 s = p->srv;
8397 while (s) {
8398 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008399 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008400 free(s->id);
8401
willy tarreaub952e1d2005-12-18 01:31:20 +01008402 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008403 free(s->cookie);
8404
8405 free(s);
8406 s = s_next;
8407 }/* end while(s) */
8408
8409 l = p->listen;
8410 while (l) {
8411 l_next = l->next;
8412 free(l);
8413 l = l_next;
8414 }/* end while(l) */
8415
8416 pool_destroy((void **) p->req_cap_pool);
8417 pool_destroy((void **) p->rsp_cap_pool);
8418 p = p->next;
8419 }/* end while(p) */
8420
8421 if (global.chroot) free(global.chroot);
8422 if (global.pidfile) free(global.pidfile);
8423
willy tarreau12350152005-12-18 01:03:27 +01008424 if (StaticReadEvent) free(StaticReadEvent);
8425 if (StaticWriteEvent) free(StaticWriteEvent);
8426 if (fdtab) free(fdtab);
8427
8428 pool_destroy(pool_session);
8429 pool_destroy(pool_buffer);
8430 pool_destroy(pool_fdtab);
8431 pool_destroy(pool_requri);
8432 pool_destroy(pool_task);
8433 pool_destroy(pool_capture);
8434 pool_destroy(pool_appsess);
8435
8436 if (have_appsession) {
8437 pool_destroy(apools.serverid);
8438 pool_destroy(apools.sessid);
8439 }
8440} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008441
willy tarreau41310e72006-03-25 18:17:56 +01008442/* sends the signal <sig> to all pids found in <oldpids> */
8443static void tell_old_pids(int sig) {
8444 int p;
8445 for (p = 0; p < nb_oldpids; p++)
8446 kill(oldpids[p], sig);
8447}
8448
willy tarreau0f7af912005-12-17 12:21:26 +01008449int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01008450 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01008451 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008452 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008453 init(argc, argv);
8454
willy tarreau0f7af912005-12-17 12:21:26 +01008455 signal(SIGQUIT, dump);
8456 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008457 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008458#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008459 signal(SIGINT, sig_int);
8460 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008461#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008462
8463 /* on very high loads, a sigpipe sometimes happen just between the
8464 * getsockopt() which tells "it's OK to write", and the following write :-(
8465 */
willy tarreau3242e862005-12-17 12:27:53 +01008466#ifndef MSG_NOSIGNAL
8467 signal(SIGPIPE, SIG_IGN);
8468#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008469
willy tarreau41310e72006-03-25 18:17:56 +01008470 /* We will loop at most 100 times with 10 ms delay each time.
8471 * That's at most 1 second. We only send a signal to old pids
8472 * if we cannot grab at least one port.
8473 */
8474 retry = MAX_START_RETRIES;
8475 err = ERR_NONE;
8476 while (retry >= 0) {
8477 struct timeval w;
8478 err = start_proxies(retry == 0 || nb_oldpids == 0);
8479 if (err != ERR_RETRYABLE)
8480 break;
8481 if (nb_oldpids == 0)
8482 break;
8483
8484 tell_old_pids(SIGTTOU);
8485 /* give some time to old processes to stop listening */
8486 w.tv_sec = 0;
8487 w.tv_usec = 10*1000;
8488 select(0, NULL, NULL, NULL, &w);
8489 retry--;
8490 }
8491
8492 /* Note: start_proxies() sends an alert when it fails. */
8493 if (err != ERR_NONE) {
8494 if (retry != MAX_START_RETRIES && nb_oldpids)
8495 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01008496 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01008497 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008498
8499 if (listeners == 0) {
8500 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008501 /* Note: we don't have to send anything to the old pids because we
8502 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01008503 exit(1);
8504 }
8505
willy tarreaudbd3bef2006-01-20 19:35:18 +01008506 /* prepare pause/play signals */
8507 signal(SIGTTOU, sig_pause);
8508 signal(SIGTTIN, sig_listen);
8509
Willy TARREAUe3283d12006-03-01 22:15:29 +01008510 if (global.mode & MODE_DAEMON) {
8511 global.mode &= ~MODE_VERBOSE;
8512 global.mode |= MODE_QUIET;
8513 }
8514
willy tarreaud0fb4652005-12-18 01:32:04 +01008515 /* MODE_QUIET can inhibit alerts and warnings below this line */
8516
8517 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008518 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008519 /* detach from the tty */
8520 fclose(stdin); fclose(stdout); fclose(stderr);
8521 close(0); close(1); close(2);
8522 }
willy tarreau0f7af912005-12-17 12:21:26 +01008523
willy tarreaufe2c5c12005-12-17 14:14:34 +01008524 /* open log & pid files before the chroot */
8525 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8526 int pidfd;
8527 unlink(global.pidfile);
8528 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8529 if (pidfd < 0) {
8530 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01008531 if (nb_oldpids)
8532 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01008533 exit(1);
8534 }
8535 pidfile = fdopen(pidfd, "w");
8536 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008537
8538 /* chroot if needed */
8539 if (global.chroot != NULL) {
8540 if (chroot(global.chroot) == -1) {
8541 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01008542 if (nb_oldpids)
8543 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01008544 }
8545 chdir("/");
8546 }
8547
willy tarreaub1285d52005-12-18 01:20:14 +01008548 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01008549 if (!global.rlimit_nofile)
8550 global.rlimit_nofile = global.maxsock;
8551
willy tarreaub1285d52005-12-18 01:20:14 +01008552 if (global.rlimit_nofile) {
8553 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8554 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8555 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8556 }
willy tarreau746e26b2006-03-25 11:14:35 +01008557 }
8558
8559 if (global.rlimit_memmax) {
8560 limit.rlim_cur = limit.rlim_max =
8561 global.rlimit_memmax * 1048576 / global.nbproc;
8562#ifdef RLIMIT_AS
8563 if (setrlimit(RLIMIT_AS, &limit) == -1) {
8564 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8565 argv[0], global.rlimit_memmax);
8566 }
8567#else
8568 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
8569 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8570 argv[0], global.rlimit_memmax);
8571 }
8572#endif
willy tarreaub1285d52005-12-18 01:20:14 +01008573 }
8574
willy tarreau41310e72006-03-25 18:17:56 +01008575 if (nb_oldpids)
8576 tell_old_pids(oldpids_sig);
8577
8578 /* Note that any error at this stage will be fatal because we will not
8579 * be able to restart the old pids.
8580 */
8581
willy tarreau9fe663a2005-12-17 13:02:59 +01008582 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008583 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008584 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8585 exit(1);
8586 }
8587
willy tarreau036e1ce2005-12-17 13:46:33 +01008588 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008589 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8590 exit(1);
8591 }
8592
willy tarreaub1285d52005-12-18 01:20:14 +01008593 /* check ulimits */
8594 limit.rlim_cur = limit.rlim_max = 0;
8595 getrlimit(RLIMIT_NOFILE, &limit);
8596 if (limit.rlim_cur < global.maxsock) {
8597 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",
8598 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8599 }
8600
willy tarreau9fe663a2005-12-17 13:02:59 +01008601 if (global.mode & MODE_DAEMON) {
8602 int ret = 0;
8603 int proc;
8604
8605 /* the father launches the required number of processes */
8606 for (proc = 0; proc < global.nbproc; proc++) {
8607 ret = fork();
8608 if (ret < 0) {
8609 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008610 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01008611 exit(1); /* there has been an error */
8612 }
8613 else if (ret == 0) /* child breaks here */
8614 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008615 if (pidfile != NULL) {
8616 fprintf(pidfile, "%d\n", ret);
8617 fflush(pidfile);
8618 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008619 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008620 /* close the pidfile both in children and father */
8621 if (pidfile != NULL)
8622 fclose(pidfile);
8623 free(global.pidfile);
8624
willy tarreau9fe663a2005-12-17 13:02:59 +01008625 if (proc == global.nbproc)
8626 exit(0); /* parent must leave */
8627
willy tarreau750a4722005-12-17 13:21:24 +01008628 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8629 * that we can detach from the TTY. We MUST NOT do it in other cases since
8630 * it would have already be done, and 0-2 would have been affected to listening
8631 * sockets
8632 */
8633 if (!(global.mode & MODE_QUIET)) {
8634 /* detach from the tty */
8635 fclose(stdin); fclose(stdout); fclose(stderr);
8636 close(0); close(1); close(2); /* close all fd's */
8637 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8638 }
willy tarreaua1598082005-12-17 13:08:06 +01008639 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008640 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008641 }
8642
willy tarreau1c2ad212005-12-18 01:11:29 +01008643#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008644 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008645 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8646 epoll_loop(POLL_LOOP_ACTION_RUN);
8647 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008648 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008649 }
8650 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008651 Warning("epoll() is not available. Using poll()/select() instead.\n");
8652 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008653 }
8654 }
8655#endif
8656
8657#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008658 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008659 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8660 poll_loop(POLL_LOOP_ACTION_RUN);
8661 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008662 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008663 }
8664 else {
8665 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008666 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008667 }
8668 }
8669#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008670 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008671 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8672 select_loop(POLL_LOOP_ACTION_RUN);
8673 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008674 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008675 }
8676 }
8677
willy tarreau0f7af912005-12-17 12:21:26 +01008678
willy tarreau12350152005-12-18 01:03:27 +01008679 /* Free all Hash Keys and all Hash elements */
8680 appsession_cleanup();
8681 /* Do some cleanup */
8682 deinit();
8683
willy tarreau0f7af912005-12-17 12:21:26 +01008684 exit(0);
8685}
willy tarreau12350152005-12-18 01:03:27 +01008686
8687#if defined(DEBUG_HASH)
8688static void print_table(const CHTbl *htbl) {
8689
8690 ListElmt *element;
8691 int i;
8692 appsess *asession;
8693
8694 /*****************************************************************************
8695 * *
8696 * Display the chained hash table. *
8697 * *
8698 *****************************************************************************/
8699
8700 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8701
8702 for (i = 0; i < TBLSIZ; i++) {
8703 fprintf(stdout, "Bucket[%03d]\n", i);
8704
8705 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8706 //fprintf(stdout, "%c", *(char *)list_data(element));
8707 asession = (appsess *)list_data(element);
8708 fprintf(stdout, "ELEM :%s:", asession->sessid);
8709 fprintf(stdout, " Server :%s: \n", asession->serverid);
8710 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8711 }
8712
8713 fprintf(stdout, "\n");
8714 }
8715 return;
8716} /* end print_table */
8717#endif
8718
8719static int appsession_init(void)
8720{
8721 static int initialized = 0;
8722 int idlen;
8723 struct server *s;
8724 struct proxy *p = proxy;
8725
8726 if (!initialized) {
8727 if (!appsession_task_init()) {
8728 apools.sessid = NULL;
8729 apools.serverid = NULL;
8730 apools.ser_waste = 0;
8731 apools.ser_use = 0;
8732 apools.ser_msize = sizeof(void *);
8733 apools.ses_waste = 0;
8734 apools.ses_use = 0;
8735 apools.ses_msize = sizeof(void *);
8736 while (p) {
8737 s = p->srv;
8738 if (apools.ses_msize < p->appsession_len)
8739 apools.ses_msize = p->appsession_len;
8740 while (s) {
8741 idlen = strlen(s->id);
8742 if (apools.ser_msize < idlen)
8743 apools.ser_msize = idlen;
8744 s = s->next;
8745 }
8746 p = p->next;
8747 }
8748 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8749 apools.ses_msize ++;
8750 }
8751 else {
8752 fprintf(stderr, "appsession_task_init failed\n");
8753 return -1;
8754 }
8755 initialized ++;
8756 }
8757 return 0;
8758}
8759
8760static int appsession_task_init(void)
8761{
8762 static int initialized = 0;
8763 struct task *t;
8764 if (!initialized) {
8765 if ((t = pool_alloc(task)) == NULL)
8766 return -1;
8767 t->next = t->prev = t->rqnext = NULL;
8768 t->wq = LIST_HEAD(wait_queue);
8769 t->state = TASK_IDLE;
8770 t->context = NULL;
8771 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8772 task_queue(t);
8773 t->process = appsession_refresh;
8774 initialized ++;
8775 }
8776 return 0;
8777}
8778
8779static int appsession_refresh(struct task *t) {
8780 struct proxy *p = proxy;
8781 CHTbl *htbl;
8782 ListElmt *element, *last;
8783 int i;
8784 appsess *asession;
8785 void *data;
8786
8787 while (p) {
8788 if (p->appsession_name != NULL) {
8789 htbl = &p->htbl_proxy;
8790 /* if we ever give up the use of TBLSIZ, we need to change this */
8791 for (i = 0; i < TBLSIZ; i++) {
8792 last = NULL;
8793 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8794 asession = (appsess *)list_data(element);
8795 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8796 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8797 int len;
8798 /*
8799 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8800 */
8801 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8802 asession->sessid, asession->serverid?asession->serverid:"(null)");
8803 write(1, trash, len);
8804 }
8805 /* delete the expired element from within the hash table */
8806 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8807 && (htbl->table[i].destroy != NULL)) {
8808 htbl->table[i].destroy(data);
8809 }
8810 if (last == NULL) {/* patient lost his head, get a new one */
8811 element = list_head(&htbl->table[i]);
8812 if (element == NULL) break; /* no heads left, go to next patient */
8813 }
8814 else
8815 element = last;
8816 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8817 else
8818 last = element;
8819 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8820 }
8821 }
8822 p = p->next;
8823 }
8824 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8825 return TBLCHKINT;
8826} /* end appsession_refresh */
8827