blob: 113d0b5f2de9957ac0af6eca1a5cc21109cf89bc [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
91#define HAPROXY_VERSION "1.2.10.1"
92#endif
93
94#ifndef HAPROXY_DATE
95#define HAPROXY_DATE "2006/03/23"
96#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 tarreau5cbea6f2005-12-17 12:48:26 +0100431
432/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100433#define SRV_RUNNING 1 /* the server is UP */
434#define SRV_BACKUP 2 /* this server is a backup server */
435#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100436#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100437#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100438
willy tarreaue39cd132005-12-17 13:00:18 +0100439/* what to do when a header matches a regex */
440#define ACT_ALLOW 0 /* allow the request */
441#define ACT_REPLACE 1 /* replace the matching header */
442#define ACT_REMOVE 2 /* remove the matching header */
443#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100444#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100445
willy tarreau9fe663a2005-12-17 13:02:59 +0100446/* configuration sections */
447#define CFG_NONE 0
448#define CFG_GLOBAL 1
449#define CFG_LISTEN 2
450
willy tarreaua1598082005-12-17 13:08:06 +0100451/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100452#define LW_DATE 1 /* date */
453#define LW_CLIP 2 /* CLient IP */
454#define LW_SVIP 4 /* SerVer IP */
455#define LW_SVID 8 /* server ID */
456#define LW_REQ 16 /* http REQuest */
457#define LW_RESP 32 /* http RESPonse */
458#define LW_PXIP 64 /* proxy IP */
459#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100460#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100461#define LW_COOKIE 512 /* captured cookie */
462#define LW_REQHDR 1024 /* request header(s) */
463#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100464
willy tarreau0f7af912005-12-17 12:21:26 +0100465/*********************************************************************/
466
467#define LIST_HEAD(a) ((void *)(&(a)))
468
469/*********************************************************************/
470
willy tarreau4302f492005-12-18 01:00:37 +0100471struct cap_hdr {
472 struct cap_hdr *next;
473 char *name; /* header name, case insensitive */
474 int namelen; /* length of the header name, to speed-up lookups */
475 int len; /* capture length, not including terminal zero */
476 int index; /* index in the output array */
477 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
478};
479
willy tarreau0f7af912005-12-17 12:21:26 +0100480struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100481 struct hdr_exp *next;
482 regex_t *preg; /* expression to look for */
483 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
484 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100485};
486
487struct buffer {
488 unsigned int l; /* data length */
489 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100490 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100491 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100492 char data[BUFSIZE];
493};
494
495struct server {
496 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100497 int state; /* server state (SRV_*) */
498 int cklen; /* the len of the cookie, to speed up checks */
499 char *cookie; /* the id set in the cookie */
500 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100501 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100502 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100503 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100504 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100505 int rise, fall; /* time in iterations */
506 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100507 int result; /* 0 = connect OK, -1 = connect KO */
508 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100509 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100510};
511
willy tarreau5cbea6f2005-12-17 12:48:26 +0100512/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100513struct task {
514 struct task *next, *prev; /* chaining ... */
515 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100516 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100517 int state; /* task state : IDLE or RUNNING */
518 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100519 int (*process)(struct task *t); /* the function which processes the task */
520 void *context; /* the task's context */
521};
522
523/* WARNING: if new fields are added, they must be initialized in event_accept() */
524struct session {
525 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100526 /* application specific below */
527 struct timeval crexpire; /* expiration date for a client read */
528 struct timeval cwexpire; /* expiration date for a client write */
529 struct timeval srexpire; /* expiration date for a server read */
530 struct timeval swexpire; /* expiration date for a server write */
531 struct timeval cnexpire; /* expiration date for a connect */
532 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
533 struct proxy *proxy; /* the proxy this socket belongs to */
534 int cli_fd; /* the client side fd */
535 int srv_fd; /* the server side fd */
536 int cli_state; /* state of the client side */
537 int srv_state; /* state of the server side */
538 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100539 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100540 struct buffer *req; /* request buffer */
541 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100542 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100543 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100544 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100545 char **req_cap; /* array of captured request headers (may be NULL) */
546 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100547 struct {
548 int logwait; /* log fields waiting to be collected : LW_* */
549 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
550 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
551 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
552 long t_data; /* delay before the first data byte from the server ... */
553 unsigned long t_close; /* total session duration */
554 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100555 char *cli_cookie; /* cookie presented by the client, in capture mode */
556 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100557 int status; /* HTTP status from the server, negative if from proxy */
558 long long bytes; /* number of bytes transferred from the server */
559 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100560 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100561};
562
willy tarreaua41a8b42005-12-17 14:02:24 +0100563struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100564 int fd; /* the listen socket */
565 struct sockaddr_storage addr; /* the address we listen to */
566 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100567};
568
569
willy tarreau0f7af912005-12-17 12:21:26 +0100570struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100571 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100572 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 +0100573 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100574 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100575 struct server *srv, *cursrv; /* known servers, current server */
willy tarreau62084d42006-03-24 18:57:41 +0100576 int srv_act, srv_bck; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100577 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100578 int cookie_len; /* strlen(cookie_name), computed only once */
579 char *appsession_name; /* name of the cookie to look for */
580 int appsession_name_len; /* strlen(appsession_name), computed only once */
581 int appsession_len; /* length of the appsession cookie value to be used */
582 int appsession_timeout;
583 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100584 char *capture_name; /* beginning of the name of the cookie to capture */
585 int capture_namelen; /* length of the cookie name to match */
586 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100587 int clitimeout; /* client I/O timeout (in milliseconds) */
588 int srvtimeout; /* server I/O timeout (in milliseconds) */
589 int contimeout; /* connect timeout (in milliseconds) */
590 char *id; /* proxy id */
591 int nbconn; /* # of active sessions */
592 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100593 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100594 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100595 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100596 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100597 struct proxy *next;
598 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100599 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100600 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100601 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100602 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100603 int nb_reqadd, nb_rspadd;
604 struct hdr_exp *req_exp; /* regular expressions for request headers */
605 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100606 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
607 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
608 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
609 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100610 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100611 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100612 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
613 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100614 struct {
615 char *msg400; /* message for error 400 */
616 int len400; /* message length for error 400 */
617 char *msg403; /* message for error 403 */
618 int len403; /* message length for error 403 */
619 char *msg408; /* message for error 408 */
620 int len408; /* message length for error 408 */
621 char *msg500; /* message for error 500 */
622 int len500; /* message length for error 500 */
623 char *msg502; /* message for error 502 */
624 int len502; /* message length for error 502 */
625 char *msg503; /* message for error 503 */
626 int len503; /* message length for error 503 */
627 char *msg504; /* message for error 504 */
628 int len504; /* message length for error 504 */
629 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100630};
631
632/* info about one given fd */
633struct fdtab {
634 int (*read)(int fd); /* read function */
635 int (*write)(int fd); /* write function */
636 struct task *owner; /* the session (or proxy) associated with this fd */
637 int state; /* the state of this fd */
638};
639
640/*********************************************************************/
641
willy tarreaub952e1d2005-12-18 01:31:20 +0100642int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100643int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100644char *cfg_cfgfile = NULL; /* configuration file */
645char *progname = NULL; /* program name */
646int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100647
648/* global options */
649static struct {
650 int uid;
651 int gid;
652 int nbproc;
653 int maxconn;
654 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100655 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100656 int mode;
657 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100658 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100659 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100660 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100661 struct sockaddr_in logsrv1, logsrv2;
662} global = {
663 logfac1 : -1,
664 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100665 loglev1 : 7, /* max syslog level : debug */
666 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100667 /* others NULL OK */
668};
669
willy tarreau0f7af912005-12-17 12:21:26 +0100670/*********************************************************************/
671
willy tarreau1c2ad212005-12-18 01:11:29 +0100672fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100673 *StaticWriteEvent;
674
willy tarreau64a3cc32005-12-18 01:13:11 +0100675int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100676
willy tarreau0f7af912005-12-17 12:21:26 +0100677void **pool_session = NULL,
678 **pool_buffer = NULL,
679 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100680 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100681 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100682 **pool_capture = NULL,
683 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100684
685struct proxy *proxy = NULL; /* list of all existing proxies */
686struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100687struct task *rq = NULL; /* global run queue */
688struct task wait_queue = { /* global wait queue */
689 prev:LIST_HEAD(wait_queue),
690 next:LIST_HEAD(wait_queue)
691};
willy tarreau0f7af912005-12-17 12:21:26 +0100692
willy tarreau0f7af912005-12-17 12:21:26 +0100693static int totalconn = 0; /* total # of terminated sessions */
694static int actconn = 0; /* # of active sessions */
695static int maxfd = 0; /* # of the highest fd + 1 */
696static int listeners = 0; /* # of listeners */
697static int stopping = 0; /* non zero means stopping in progress */
698static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100699static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100700
willy tarreau08dedbe2005-12-18 01:13:48 +0100701#if defined(ENABLE_EPOLL)
702/* FIXME: this is dirty, but at the moment, there's no other solution to remove
703 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
704 * structure with pointers to functions such as init_fd() and close_fd(), plus
705 * a private structure with several pointers to places such as below.
706 */
707
708static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
709#endif
710
willy tarreau0f7af912005-12-17 12:21:26 +0100711static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100712/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100713static char trash[BUFSIZE];
714
willy tarreaudd07e972005-12-18 00:48:48 +0100715const int zero = 0;
716const int one = 1;
717
willy tarreau0f7af912005-12-17 12:21:26 +0100718/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100719 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100720 */
721
722#define MAX_SYSLOG_LEN 1024
723#define NB_LOG_FACILITIES 24
724const char *log_facilities[NB_LOG_FACILITIES] = {
725 "kern", "user", "mail", "daemon",
726 "auth", "syslog", "lpr", "news",
727 "uucp", "cron", "auth2", "ftp",
728 "ntp", "audit", "alert", "cron2",
729 "local0", "local1", "local2", "local3",
730 "local4", "local5", "local6", "local7"
731};
732
733
734#define NB_LOG_LEVELS 8
735const char *log_levels[NB_LOG_LEVELS] = {
736 "emerg", "alert", "crit", "err",
737 "warning", "notice", "info", "debug"
738};
739
740#define SYSLOG_PORT 514
741
742const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
743 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100744
willy tarreaub1285d52005-12-18 01:20:14 +0100745const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100746const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
747const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
748const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
749 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
750 unknown, Set-cookie Rewritten */
751
willy tarreau0f7af912005-12-17 12:21:26 +0100752#define MAX_HOSTNAME_LEN 32
753static char hostname[MAX_HOSTNAME_LEN] = "";
754
willy tarreau8337c6b2005-12-17 13:41:01 +0100755const char *HTTP_302 =
756 "HTTP/1.0 302 Found\r\n"
757 "Cache-Control: no-cache\r\n"
758 "Connection: close\r\n"
759 "Location: "; /* not terminated since it will be concatenated with the URL */
760
willy tarreauc1f47532005-12-18 01:08:26 +0100761/* same as 302 except that the browser MUST retry with the GET method */
762const char *HTTP_303 =
763 "HTTP/1.0 303 See Other\r\n"
764 "Cache-Control: no-cache\r\n"
765 "Connection: close\r\n"
766 "Location: "; /* not terminated since it will be concatenated with the URL */
767
willy tarreaua1598082005-12-17 13:08:06 +0100768const char *HTTP_400 =
769 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100770 "Cache-Control: no-cache\r\n"
771 "Connection: close\r\n"
772 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100773 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100774
willy tarreaua1598082005-12-17 13:08:06 +0100775const char *HTTP_403 =
776 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100777 "Cache-Control: no-cache\r\n"
778 "Connection: close\r\n"
779 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100780 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
781
willy tarreau8337c6b2005-12-17 13:41:01 +0100782const char *HTTP_408 =
783 "HTTP/1.0 408 Request Time-out\r\n"
784 "Cache-Control: no-cache\r\n"
785 "Connection: close\r\n"
786 "\r\n"
787 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
788
willy tarreau750a4722005-12-17 13:21:24 +0100789const char *HTTP_500 =
790 "HTTP/1.0 500 Server Error\r\n"
791 "Cache-Control: no-cache\r\n"
792 "Connection: close\r\n"
793 "\r\n"
794 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100795
796const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100797 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100798 "Cache-Control: no-cache\r\n"
799 "Connection: close\r\n"
800 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100801 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
802
803const char *HTTP_503 =
804 "HTTP/1.0 503 Service Unavailable\r\n"
805 "Cache-Control: no-cache\r\n"
806 "Connection: close\r\n"
807 "\r\n"
808 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
809
810const char *HTTP_504 =
811 "HTTP/1.0 504 Gateway Time-out\r\n"
812 "Cache-Control: no-cache\r\n"
813 "Connection: close\r\n"
814 "\r\n"
815 "<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 +0100816
willy tarreau0f7af912005-12-17 12:21:26 +0100817/*********************************************************************/
818/* statistics ******************************************************/
819/*********************************************************************/
820
willy tarreau750a4722005-12-17 13:21:24 +0100821#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100822static int stats_tsk_lsrch, stats_tsk_rsrch,
823 stats_tsk_good, stats_tsk_right, stats_tsk_left,
824 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100825#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100826
827
828/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100829/* debugging *******************************************************/
830/*********************************************************************/
831#ifdef DEBUG_FULL
832static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
833static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
834#endif
835
836/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100837/* function prototypes *********************************************/
838/*********************************************************************/
839
840int event_accept(int fd);
841int event_cli_read(int fd);
842int event_cli_write(int fd);
843int event_srv_read(int fd);
844int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100845int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100846
willy tarreau12350152005-12-18 01:03:27 +0100847static int appsession_task_init(void);
848static int appsession_init(void);
849static int appsession_refresh(struct task *t);
850
willy tarreau0f7af912005-12-17 12:21:26 +0100851/*********************************************************************/
852/* general purpose functions ***************************************/
853/*********************************************************************/
854
855void display_version() {
856 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100857 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100858}
859
860/*
861 * This function prints the command line usage and exits
862 */
863void usage(char *name) {
864 display_version();
865 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100866 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100867#if STATTIME > 0
868 "sl"
869#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100870 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100871 " -v displays version\n"
872 " -d enters debug mode\n"
willy tarreau982249e2005-12-18 00:57:06 +0100873 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100874#if STATTIME > 0
875 " -s enables statistics output\n"
876 " -l enables long statistics format\n"
877#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100878 " -D goes daemon ; implies -q\n"
879 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100880 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100881 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100882 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100883 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100884#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100885 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100886#endif
887#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100888 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100889#endif
willy tarreauad90a0c2005-12-18 01:09:15 +0100890 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100891 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100892 exit(1);
893}
894
895
896/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100897 * Displays the message on stderr with the date and pid. Overrides the quiet
898 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100899 */
900void Alert(char *fmt, ...) {
901 va_list argp;
902 struct timeval tv;
903 struct tm *tm;
904
willy tarreaud0fb4652005-12-18 01:32:04 +0100905 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100906 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100907
willy tarreau5cbea6f2005-12-17 12:48:26 +0100908 gettimeofday(&tv, NULL);
909 tm=localtime(&tv.tv_sec);
910 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100911 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100912 vfprintf(stderr, fmt, argp);
913 fflush(stderr);
914 va_end(argp);
915 }
willy tarreau0f7af912005-12-17 12:21:26 +0100916}
917
918
919/*
920 * Displays the message on stderr with the date and pid.
921 */
922void Warning(char *fmt, ...) {
923 va_list argp;
924 struct timeval tv;
925 struct tm *tm;
926
willy tarreau982249e2005-12-18 00:57:06 +0100927 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100928 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100929
willy tarreau5cbea6f2005-12-17 12:48:26 +0100930 gettimeofday(&tv, NULL);
931 tm=localtime(&tv.tv_sec);
932 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100933 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100934 vfprintf(stderr, fmt, argp);
935 fflush(stderr);
936 va_end(argp);
937 }
938}
939
940/*
941 * Displays the message on <out> only if quiet mode is not set.
942 */
943void qfprintf(FILE *out, char *fmt, ...) {
944 va_list argp;
945
willy tarreau982249e2005-12-18 00:57:06 +0100946 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100947 va_start(argp, fmt);
948 vfprintf(out, fmt, argp);
949 fflush(out);
950 va_end(argp);
951 }
willy tarreau0f7af912005-12-17 12:21:26 +0100952}
953
954
955/*
956 * converts <str> to a struct sockaddr_in* which is locally allocated.
957 * The format is "addr:port", where "addr" can be empty or "*" to indicate
958 * INADDR_ANY.
959 */
960struct sockaddr_in *str2sa(char *str) {
961 static struct sockaddr_in sa;
962 char *c;
963 int port;
964
willy tarreaua1598082005-12-17 13:08:06 +0100965 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100966 str=strdup(str);
967
968 if ((c=strrchr(str,':')) != NULL) {
969 *c++=0;
970 port=atol(c);
971 }
972 else
973 port=0;
974
975 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
976 sa.sin_addr.s_addr = INADDR_ANY;
977 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100978 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100979 struct hostent *he;
980
981 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100982 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100983 }
984 else
985 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
986 }
987 sa.sin_port=htons(port);
988 sa.sin_family=AF_INET;
989
990 free(str);
991 return &sa;
992}
993
willy tarreaub1285d52005-12-18 01:20:14 +0100994/*
995 * converts <str> to a two struct in_addr* which are locally allocated.
996 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
997 * is optionnal and either in the dotted or CIDR notation.
998 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
999 */
1000int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1001 char *c;
1002 unsigned long len;
1003
1004 memset(mask, 0, sizeof(*mask));
1005 memset(addr, 0, sizeof(*addr));
1006 str=strdup(str);
1007
1008 if ((c = strrchr(str, '/')) != NULL) {
1009 *c++ = 0;
1010 /* c points to the mask */
1011 if (strchr(c, '.') != NULL) { /* dotted notation */
1012 if (!inet_pton(AF_INET, c, mask))
1013 return 0;
1014 }
1015 else { /* mask length */
1016 char *err;
1017 len = strtol(c, &err, 10);
1018 if (!*c || (err && *err) || (unsigned)len > 32)
1019 return 0;
1020 if (len)
1021 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1022 else
1023 mask->s_addr = 0;
1024 }
1025 }
1026 else {
1027 mask->s_addr = 0xFFFFFFFF;
1028 }
1029 if (!inet_pton(AF_INET, str, addr)) {
1030 struct hostent *he;
1031
1032 if ((he = gethostbyname(str)) == NULL) {
1033 return 0;
1034 }
1035 else
1036 *addr = *(struct in_addr *) *(he->h_addr_list);
1037 }
1038 free(str);
1039 return 1;
1040}
1041
willy tarreau9fe663a2005-12-17 13:02:59 +01001042
1043/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001044 * converts <str> to a list of listeners which are dynamically allocated.
1045 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1046 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1047 * - <port> is a numerical port from 1 to 65535 ;
1048 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1049 * This can be repeated as many times as necessary, separated by a coma.
1050 * The <tail> argument is a pointer to a current list which should be appended
1051 * to the tail of the new list. The pointer to the new list is returned.
1052 */
1053struct listener *str2listener(char *str, struct listener *tail) {
1054 struct listener *l;
1055 char *c, *next, *range, *dupstr;
1056 int port, end;
1057
1058 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001059
willy tarreaua41a8b42005-12-17 14:02:24 +01001060 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001061 struct sockaddr_storage ss;
1062
willy tarreaua41a8b42005-12-17 14:02:24 +01001063 str = next;
1064 /* 1) look for the end of the first address */
1065 if ((next = strrchr(str, ',')) != NULL) {
1066 *next++ = 0;
1067 }
1068
willy tarreau8a86dbf2005-12-18 00:45:59 +01001069 /* 2) look for the addr/port delimiter, it's the last colon. */
1070 if ((range = strrchr(str, ':')) == NULL) {
1071 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001072 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001073 }
1074
1075 *range++ = 0;
1076
1077 if (strrchr(str, ':') != NULL) {
1078 /* IPv6 address contains ':' */
1079 memset(&ss, 0, sizeof(ss));
1080 ss.ss_family = AF_INET6;
1081
1082 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1083 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001084 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001085 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001086 }
1087 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001088 memset(&ss, 0, sizeof(ss));
1089 ss.ss_family = AF_INET;
1090
1091 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1092 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1093 }
1094 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1095 struct hostent *he;
1096
1097 if ((he = gethostbyname(str)) == NULL) {
1098 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001099 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001100 }
1101 else
1102 ((struct sockaddr_in *)&ss)->sin_addr =
1103 *(struct in_addr *) *(he->h_addr_list);
1104 }
1105 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001106
1107 /* 3) look for the port-end delimiter */
1108 if ((c = strchr(range, '-')) != NULL) {
1109 *c++ = 0;
1110 end = atol(c);
1111 }
1112 else {
1113 end = atol(range);
1114 }
1115
willy tarreaud0fb4652005-12-18 01:32:04 +01001116 port = atol(range);
1117
1118 if (port < 1 || port > 65535) {
1119 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1120 goto fail;
1121 }
1122
1123 if (end < 1 || end > 65535) {
1124 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1125 goto fail;
1126 }
1127
1128 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001129 l = (struct listener *)calloc(1, sizeof(struct listener));
1130 l->next = tail;
1131 tail = l;
1132
willy tarreau8a86dbf2005-12-18 00:45:59 +01001133 l->addr = ss;
1134 if (ss.ss_family == AF_INET6)
1135 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1136 else
1137 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1138
willy tarreaua41a8b42005-12-17 14:02:24 +01001139 } /* end for(port) */
1140 } /* end while(next) */
1141 free(dupstr);
1142 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001143 fail:
1144 free(dupstr);
1145 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001146}
1147
willy tarreau4302f492005-12-18 01:00:37 +01001148
1149#define FD_SETS_ARE_BITFIELDS
1150#ifdef FD_SETS_ARE_BITFIELDS
1151/*
1152 * This map is used with all the FD_* macros to check whether a particular bit
1153 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1154 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1155 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1156 * exclusively to the macros.
1157 */
1158fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1159fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1160
1161#else
1162#error "Check if your OS uses bitfields for fd_sets"
1163#endif
1164
1165/* will try to encode the string <string> replacing all characters tagged in
1166 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1167 * prefixed by <escape>, and will store the result between <start> (included
1168 *) and <stop> (excluded), and will always terminate the string with a '\0'
1169 * before <stop>. The position of the '\0' is returned if the conversion
1170 * completes. If bytes are missing between <start> and <stop>, then the
1171 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1172 * cannot even be stored so we return <start> without writing the 0.
1173 * The input string must also be zero-terminated.
1174 */
1175char hextab[16] = "0123456789ABCDEF";
1176char *encode_string(char *start, char *stop,
1177 const char escape, const fd_set *map,
1178 const char *string)
1179{
1180 if (start < stop) {
1181 stop--; /* reserve one byte for the final '\0' */
1182 while (start < stop && *string != 0) {
1183 if (!FD_ISSET((unsigned char)(*string), map))
1184 *start++ = *string;
1185 else {
1186 if (start + 3 >= stop)
1187 break;
1188 *start++ = escape;
1189 *start++ = hextab[(*string >> 4) & 15];
1190 *start++ = hextab[*string & 15];
1191 }
1192 string++;
1193 }
1194 *start = '\0';
1195 }
1196 return start;
1197}
willy tarreaua41a8b42005-12-17 14:02:24 +01001198
1199/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001200 * This function sends a syslog message to both log servers of a proxy,
1201 * or to global log servers if the proxy is NULL.
1202 * It also tries not to waste too much time computing the message header.
1203 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001204 */
1205void send_log(struct proxy *p, int level, char *message, ...) {
1206 static int logfd = -1; /* syslog UDP socket */
1207 static long tvsec = -1; /* to force the string to be initialized */
1208 struct timeval tv;
1209 va_list argp;
1210 static char logmsg[MAX_SYSLOG_LEN];
1211 static char *dataptr = NULL;
1212 int fac_level;
1213 int hdr_len, data_len;
1214 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001215 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001216 int nbloggers = 0;
1217 char *log_ptr;
1218
1219 if (logfd < 0) {
1220 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1221 return;
1222 }
1223
1224 if (level < 0 || progname == NULL || message == NULL)
1225 return;
1226
1227 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001228 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001229 /* this string is rebuild only once a second */
1230 struct tm *tm = localtime(&tv.tv_sec);
1231 tvsec = tv.tv_sec;
1232
willy tarreauc29948c2005-12-17 13:10:27 +01001233 hdr_len = snprintf(logmsg, sizeof(logmsg),
1234 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1235 monthname[tm->tm_mon],
1236 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1237 progname, pid);
1238 /* WARNING: depending upon implementations, snprintf may return
1239 * either -1 or the number of bytes that would be needed to store
1240 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001241 */
willy tarreauc29948c2005-12-17 13:10:27 +01001242 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1243 hdr_len = sizeof(logmsg);
1244
1245 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001246 }
1247
1248 va_start(argp, message);
1249 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001250 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1251 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001252 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001253 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001254
1255 if (p == NULL) {
1256 if (global.logfac1 >= 0) {
1257 sa[nbloggers] = &global.logsrv1;
1258 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001259 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001260 nbloggers++;
1261 }
1262 if (global.logfac2 >= 0) {
1263 sa[nbloggers] = &global.logsrv2;
1264 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001265 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001266 nbloggers++;
1267 }
1268 } else {
1269 if (p->logfac1 >= 0) {
1270 sa[nbloggers] = &p->logsrv1;
1271 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001272 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001273 nbloggers++;
1274 }
1275 if (p->logfac2 >= 0) {
1276 sa[nbloggers] = &p->logsrv2;
1277 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001278 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001279 nbloggers++;
1280 }
1281 }
1282
1283 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001284 /* we can filter the level of the messages that are sent to each logger */
1285 if (level > loglevel[nbloggers])
1286 continue;
1287
willy tarreauc29948c2005-12-17 13:10:27 +01001288 /* For each target, we may have a different facility.
1289 * We can also have a different log level for each message.
1290 * This induces variations in the message header length.
1291 * Since we don't want to recompute it each time, nor copy it every
1292 * time, we only change the facility in the pre-computed header,
1293 * and we change the pointer to the header accordingly.
1294 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001295 fac_level = (facilities[nbloggers] << 3) + level;
1296 log_ptr = logmsg + 3; /* last digit of the log level */
1297 do {
1298 *log_ptr = '0' + fac_level % 10;
1299 fac_level /= 10;
1300 log_ptr--;
1301 } while (fac_level && log_ptr > logmsg);
1302 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001303
willy tarreauc29948c2005-12-17 13:10:27 +01001304 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001305
1306#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001307 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001308 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1309#else
willy tarreauc29948c2005-12-17 13:10:27 +01001310 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001311 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1312#endif
1313 }
willy tarreau0f7af912005-12-17 12:21:26 +01001314}
1315
1316
1317/* sets <tv> to the current time */
1318static inline struct timeval *tv_now(struct timeval *tv) {
1319 if (tv)
1320 gettimeofday(tv, NULL);
1321 return tv;
1322}
1323
1324/*
1325 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1326 */
1327static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1328 if (!tv || !from)
1329 return NULL;
1330 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1331 tv->tv_sec = from->tv_sec + (ms/1000);
1332 while (tv->tv_usec >= 1000000) {
1333 tv->tv_usec -= 1000000;
1334 tv->tv_sec++;
1335 }
1336 return tv;
1337}
1338
1339/*
1340 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001341 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001342 */
1343static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001344 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001345 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001346 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001347 return 1;
1348 else if (tv1->tv_usec < tv2->tv_usec)
1349 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001350 else if (tv1->tv_usec > tv2->tv_usec)
1351 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001352 else
1353 return 0;
1354}
1355
1356/*
1357 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001358 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001359 */
1360unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1361 int cmp;
1362 unsigned long ret;
1363
1364
willy tarreauef900ab2005-12-17 12:52:52 +01001365 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001366 if (!cmp)
1367 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001368 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001369 struct timeval *tmp = tv1;
1370 tv1 = tv2;
1371 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001372 }
willy tarreauef900ab2005-12-17 12:52:52 +01001373 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001374 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001375 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001376 else
willy tarreauef900ab2005-12-17 12:52:52 +01001377 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001378 return (unsigned long) ret;
1379}
1380
1381/*
willy tarreau750a4722005-12-17 13:21:24 +01001382 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001383 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001384 */
1385static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1386 unsigned long ret;
1387
willy tarreau6e682ce2005-12-17 13:26:49 +01001388 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1389 if (tv2->tv_usec > tv1->tv_usec)
1390 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001391 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001392 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001393 return (unsigned long) ret;
1394}
1395
1396/*
willy tarreau0f7af912005-12-17 12:21:26 +01001397 * 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 +01001398 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001399 */
1400static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001401 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001402 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001403 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001404 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001405 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001406 else
1407 return 0;
1408 }
willy tarreau0f7af912005-12-17 12:21:26 +01001409 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001410 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001411 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001412 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001413 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001414 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001415 else
1416 return 0;
1417}
1418
1419/*
1420 * returns the remaining time between tv1=now and event=tv2
1421 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001422 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001423 */
1424static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1425 unsigned long ret;
1426
willy tarreau0f7af912005-12-17 12:21:26 +01001427 if (tv_cmp_ms(tv1, tv2) >= 0)
1428 return 0; /* event elapsed */
1429
willy tarreauef900ab2005-12-17 12:52:52 +01001430 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001431 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001432 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001433 else
willy tarreauef900ab2005-12-17 12:52:52 +01001434 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001435 return (unsigned long) ret;
1436}
1437
1438
1439/*
1440 * zeroes a struct timeval
1441 */
1442
1443static inline struct timeval *tv_eternity(struct timeval *tv) {
1444 tv->tv_sec = tv->tv_usec = 0;
1445 return tv;
1446}
1447
1448/*
1449 * returns 1 if tv is null, else 0
1450 */
1451static inline int tv_iseternity(struct timeval *tv) {
1452 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1453 return 1;
1454 else
1455 return 0;
1456}
1457
1458/*
1459 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1460 * considering that 0 is the eternity.
1461 */
1462static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1463 if (tv_iseternity(tv1))
1464 if (tv_iseternity(tv2))
1465 return 0; /* same */
1466 else
1467 return 1; /* tv1 later than tv2 */
1468 else if (tv_iseternity(tv2))
1469 return -1; /* tv2 later than tv1 */
1470
1471 if (tv1->tv_sec > tv2->tv_sec)
1472 return 1;
1473 else if (tv1->tv_sec < tv2->tv_sec)
1474 return -1;
1475 else if (tv1->tv_usec > tv2->tv_usec)
1476 return 1;
1477 else if (tv1->tv_usec < tv2->tv_usec)
1478 return -1;
1479 else
1480 return 0;
1481}
1482
1483/*
1484 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1485 * considering that 0 is the eternity.
1486 */
1487static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1488 if (tv_iseternity(tv1))
1489 if (tv_iseternity(tv2))
1490 return 0; /* same */
1491 else
1492 return 1; /* tv1 later than tv2 */
1493 else if (tv_iseternity(tv2))
1494 return -1; /* tv2 later than tv1 */
1495
willy tarreauefae1842005-12-17 12:51:03 +01001496 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001497 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001498 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001499 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001500 return -1;
1501 else
1502 return 0;
1503 }
1504 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001505 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001506 return 1;
1507 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001508 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001509 return -1;
1510 else
1511 return 0;
1512}
1513
1514/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001515 * returns the remaining time between tv1=now and event=tv2
1516 * if tv2 is passed, 0 is returned.
1517 * Returns TIME_ETERNITY if tv2 is eternity.
1518 */
1519static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1520 unsigned long ret;
1521
1522 if (tv_iseternity(tv2))
1523 return TIME_ETERNITY;
1524
1525 if (tv_cmp_ms(tv1, tv2) >= 0)
1526 return 0; /* event elapsed */
1527
1528 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1529 if (tv2->tv_usec > tv1->tv_usec)
1530 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1531 else
1532 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1533 return (unsigned long) ret;
1534}
1535
1536/*
willy tarreau0f7af912005-12-17 12:21:26 +01001537 * returns the first event between tv1 and tv2 into tvmin.
1538 * a zero tv is ignored. tvmin is returned.
1539 */
1540static inline struct timeval *tv_min(struct timeval *tvmin,
1541 struct timeval *tv1, struct timeval *tv2) {
1542
1543 if (tv_cmp2(tv1, tv2) <= 0)
1544 *tvmin = *tv1;
1545 else
1546 *tvmin = *tv2;
1547
1548 return tvmin;
1549}
1550
1551
1552
1553/***********************************************************/
1554/* fd management ***************************************/
1555/***********************************************************/
1556
1557
1558
willy tarreau5cbea6f2005-12-17 12:48:26 +01001559/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1560 * The file descriptor is also closed.
1561 */
willy tarreau0f7af912005-12-17 12:21:26 +01001562static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001563 FD_CLR(fd, StaticReadEvent);
1564 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001565#if defined(ENABLE_EPOLL)
1566 if (PrevReadEvent) {
1567 FD_CLR(fd, PrevReadEvent);
1568 FD_CLR(fd, PrevWriteEvent);
1569 }
1570#endif
1571
willy tarreau5cbea6f2005-12-17 12:48:26 +01001572 close(fd);
1573 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001574
1575 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1576 maxfd--;
1577}
1578
1579/* recomputes the maxfd limit from the fd */
1580static inline void fd_insert(int fd) {
1581 if (fd+1 > maxfd)
1582 maxfd = fd+1;
1583}
1584
1585/*************************************************************/
1586/* task management ***************************************/
1587/*************************************************************/
1588
willy tarreau5cbea6f2005-12-17 12:48:26 +01001589/* puts the task <t> in run queue <q>, and returns <t> */
1590static inline struct task *task_wakeup(struct task **q, struct task *t) {
1591 if (t->state == TASK_RUNNING)
1592 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001593 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001594 t->rqnext = *q;
1595 t->state = TASK_RUNNING;
1596 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001597 }
1598}
1599
willy tarreau5cbea6f2005-12-17 12:48:26 +01001600/* removes the task <t> from the queue <q>
1601 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001602 * set the run queue to point to the next one, and return it
1603 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001604static inline struct task *task_sleep(struct task **q, struct task *t) {
1605 if (t->state == TASK_RUNNING) {
1606 *q = t->rqnext;
1607 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001608 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001609 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001610}
1611
1612/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001613 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001614 * from the run queue. A pointer to the task itself is returned.
1615 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001616static inline struct task *task_delete(struct task *t) {
1617 t->prev->next = t->next;
1618 t->next->prev = t->prev;
1619 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001620}
1621
1622/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001623 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001624 */
1625static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001626 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001627}
1628
willy tarreau5cbea6f2005-12-17 12:48:26 +01001629/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001630 * may be only moved or left where it was, depending on its timing requirements.
1631 * <task> is returned.
1632 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001633struct task *task_queue(struct task *task) {
1634 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001635 struct task *start_from;
1636
1637 /* first, test if the task was already in a list */
1638 if (task->prev == NULL) {
1639 // start_from = list;
1640 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001641#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001642 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001643#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001644 /* insert the unlinked <task> into the list, searching back from the last entry */
1645 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1646 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001647#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001648 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001649#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001650 }
1651
1652 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1653 // start_from = start_from->next;
1654 // stats_tsk_nsrch++;
1655 // }
1656 }
1657 else if (task->prev == list ||
1658 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1659 start_from = task->next;
1660 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001661#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001662 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001663#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001664 return task; /* it's already in the right place */
1665 }
1666
willy tarreau750a4722005-12-17 13:21:24 +01001667#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001668 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001669#endif
1670
1671 /* if the task is not at the right place, there's little chance that
1672 * it has only shifted a bit, and it will nearly always be queued
1673 * at the end of the list because of constant timeouts
1674 * (observed in real case).
1675 */
1676#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1677 start_from = list->prev; /* assume we'll queue to the end of the list */
1678 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1679 start_from = start_from->prev;
1680#if STATTIME > 0
1681 stats_tsk_lsrch++;
1682#endif
1683 }
1684#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001685 /* insert the unlinked <task> into the list, searching after position <start_from> */
1686 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1687 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001688#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001689 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001690#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001691 }
willy tarreau750a4722005-12-17 13:21:24 +01001692#endif /* WE_REALLY_... */
1693
willy tarreau0f7af912005-12-17 12:21:26 +01001694 /* we need to unlink it now */
1695 task_delete(task);
1696 }
1697 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001698#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001699 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001700#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001701#ifdef LEFT_TO_TOP /* not very good */
1702 start_from = list;
1703 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1704 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001705#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001706 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001707#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001708 }
1709#else
1710 start_from = task->prev->prev; /* valid because of the previous test above */
1711 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1712 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001713#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001714 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001715#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001716 }
1717#endif
1718 /* we need to unlink it now */
1719 task_delete(task);
1720 }
1721 task->prev = start_from;
1722 task->next = start_from->next;
1723 task->next->prev = task;
1724 start_from->next = task;
1725 return task;
1726}
1727
1728
1729/*********************************************************************/
1730/* more specific functions ***************************************/
1731/*********************************************************************/
1732
1733/* some prototypes */
1734static int maintain_proxies(void);
1735
willy tarreaub952e1d2005-12-18 01:31:20 +01001736/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001737 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1738 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001739static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001740#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001741 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1742#else
willy tarreaua1598082005-12-17 13:08:06 +01001743#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001744 return getsockname(fd, (struct sockaddr *)sa, salen);
1745#else
1746 return -1;
1747#endif
1748#endif
1749}
1750
1751/*
1752 * frees the context associated to a session. It must have been removed first.
1753 */
1754static inline void session_free(struct session *s) {
1755 if (s->req)
1756 pool_free(buffer, s->req);
1757 if (s->rep)
1758 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001759
1760 if (s->rsp_cap != NULL) {
1761 struct cap_hdr *h;
1762 for (h = s->proxy->rsp_cap; h; h = h->next) {
1763 if (s->rsp_cap[h->index] != NULL)
1764 pool_free_to(h->pool, s->rsp_cap[h->index]);
1765 }
1766 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1767 }
1768 if (s->req_cap != NULL) {
1769 struct cap_hdr *h;
1770 for (h = s->proxy->req_cap; h; h = h->next) {
1771 if (s->req_cap[h->index] != NULL)
1772 pool_free_to(h->pool, s->req_cap[h->index]);
1773 }
1774 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1775 }
1776
willy tarreaua1598082005-12-17 13:08:06 +01001777 if (s->logs.uri)
1778 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001779 if (s->logs.cli_cookie)
1780 pool_free(capture, s->logs.cli_cookie);
1781 if (s->logs.srv_cookie)
1782 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001783
willy tarreau5cbea6f2005-12-17 12:48:26 +01001784 pool_free(session, s);
1785}
1786
willy tarreau0f7af912005-12-17 12:21:26 +01001787
1788/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01001789 * This function recounts the number of usable active and backup servers for
1790 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
1791 */
1792static inline void recount_servers(struct proxy *px) {
1793 struct server *srv;
1794
1795 px->srv_act = 0; px->srv_bck = 0;
1796 for (srv = px->srv; srv != NULL; srv = srv->next) {
1797 if (srv->state & SRV_RUNNING) {
1798 if (srv->state & SRV_BACKUP)
1799 px->srv_bck++;
1800 else
1801 px->srv_act++;
1802 }
1803 }
1804}
1805
1806/*
1807 * This function tries to find a running server for the proxy <px> following
1808 * the round-robin method. Depending on the number of active/backup servers,
1809 * it will either look for active servers, or for backup servers.
1810 * If any server is found, it will be returned and px->cursrv will be updated
1811 * to point to the next server. If no valid server is found, NULL is returned.
willy tarreau8337c6b2005-12-17 13:41:01 +01001812 */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001813static inline struct server *get_server_rr(struct proxy *px) {
1814 struct server *srv;
willy tarreau72e583d2006-03-23 11:27:02 +01001815 struct server *end;
willy tarreau8337c6b2005-12-17 13:41:01 +01001816
willy tarreau4c8c2b52006-03-24 19:36:41 +01001817 if (px->srv_act) {
1818 srv = px->cursrv;
willy tarreau72e583d2006-03-23 11:27:02 +01001819 if (srv == NULL)
1820 srv = px->srv;
1821 end = srv;
willy tarreau8337c6b2005-12-17 13:41:01 +01001822 do {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001823 if ((srv->state & (SRV_RUNNING | SRV_BACKUP)) == SRV_RUNNING) {
1824 px->cursrv = srv->next;
willy tarreau8337c6b2005-12-17 13:41:01 +01001825 return srv;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001826 }
1827
willy tarreau8337c6b2005-12-17 13:41:01 +01001828 srv = srv->next;
willy tarreau72e583d2006-03-23 11:27:02 +01001829 if (srv == NULL)
1830 srv = px->srv;
1831 } while (srv != end);
willy tarreau4c8c2b52006-03-24 19:36:41 +01001832 /* note that theorically we should not get there */
1833 }
Willy TARREAU3481c462006-03-01 22:37:57 +01001834
willy tarreau4c8c2b52006-03-24 19:36:41 +01001835 if (px->srv_bck) {
Willy TARREAU3481c462006-03-01 22:37:57 +01001836 /* By default, we look for the first backup server if all others are
1837 * DOWN. But in some cases, it may be desirable to load-balance across
1838 * all backup servers.
1839 */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001840 if (px->options & PR_O_USE_ALL_BK)
1841 srv = px->cursrv;
1842 else
1843 srv = px->srv;
1844
1845 if (srv == NULL)
Willy TARREAU3481c462006-03-01 22:37:57 +01001846 srv = px->srv;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001847 end = srv;
1848 do {
1849 if (srv->state & SRV_RUNNING) {
1850 px->cursrv = srv->next;
1851 return srv;
1852 }
1853 srv = srv->next;
1854 if (srv == NULL)
1855 srv = px->srv;
1856 } while (srv != end);
1857 /* note that theorically we should not get there */
1858 }
Willy TARREAU3481c462006-03-01 22:37:57 +01001859
willy tarreau4c8c2b52006-03-24 19:36:41 +01001860 /* if we get there, it means there are no available servers at all */
willy tarreau8337c6b2005-12-17 13:41:01 +01001861 return NULL;
1862}
1863
willy tarreau62084d42006-03-24 18:57:41 +01001864
1865/*
willy tarreau1a3442d2006-03-24 21:03:20 +01001866 * This function tries to find a running server for the proxy <px> following
1867 * the source hash method. Depending on the number of active/backup servers,
1868 * it will either look for active servers, or for backup servers.
1869 * If any server is found, it will be returned. If no valid server is found,
1870 * NULL is returned.
1871 */
1872static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
1873 struct server *srv;
1874
1875 if (px->srv_act) {
1876 unsigned int h, l;
1877
1878 l = h = 0;
1879 if (px->srv_act > 1) {
1880 while ((l + sizeof (int)) <= len) {
1881 h ^= ntohl(*(unsigned int *)(&addr[l]));
1882 l += sizeof (int);
1883 }
1884 h %= px->srv_act;
1885 }
1886
1887 for (srv = px->srv; srv; srv = srv->next) {
1888 if ((srv->state & (SRV_RUNNING | SRV_BACKUP)) == SRV_RUNNING) {
1889 if (!h)
1890 return srv;
1891 h--;
1892 }
1893 }
1894 /* note that theorically we should not get there */
1895 }
1896
1897 if (px->srv_bck) {
1898 unsigned int h, l;
1899
1900 /* By default, we look for the first backup server if all others are
1901 * DOWN. But in some cases, it may be desirable to load-balance across
1902 * all backup servers.
1903 */
1904 l = h = 0;
1905 if (px->srv_bck > 1 && px->options & PR_O_USE_ALL_BK) {
1906 while ((l + sizeof (int)) <= len) {
1907 h ^= ntohl(*(unsigned int *)(&addr[l]));
1908 l += sizeof (int);
1909 }
1910 h %= px->srv_bck;
1911 }
1912
1913 for (srv = px->srv; srv; srv = srv->next) {
1914 if (srv->state & SRV_RUNNING) {
1915 if (!h)
1916 return srv;
1917 h--;
1918 }
1919 }
1920 /* note that theorically we should not get there */
1921 }
1922
1923 /* if we get there, it means there are no available servers at all */
1924 return NULL;
1925}
1926
1927
1928/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001929 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01001930 * is set, or to the dispatch server if (s->direct) is 0.
1931 * It can return one of :
1932 * - SN_ERR_NONE if everything's OK
1933 * - SN_ERR_SRVTO if there are no more servers
1934 * - SN_ERR_SRVCL if the connection was refused by the server
1935 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1936 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1937 * - SN_ERR_INTERNAL for any other purely internal errors
1938 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01001939 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001940int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001941 int fd;
1942
willy tarreau12350152005-12-18 01:03:27 +01001943#ifdef DEBUG_FULL
1944 fprintf(stderr,"connect_server : s=%p\n",s);
1945#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001946
willy tarreaue39cd132005-12-17 13:00:18 +01001947 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001948 s->srv_addr = s->srv->addr;
1949 }
1950 else if (s->proxy->options & PR_O_BALANCE) {
willy tarreau1a3442d2006-03-24 21:03:20 +01001951 /* Ensure that srv will not be NULL */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001952 if (!s->proxy->srv_act && !s->proxy->srv_bck)
1953 return SN_ERR_SRVTO;
1954
willy tarreau5cbea6f2005-12-17 12:48:26 +01001955 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001956 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001957
willy tarreau4c8c2b52006-03-24 19:36:41 +01001958 srv = get_server_rr(s->proxy);
willy tarreau8337c6b2005-12-17 13:41:01 +01001959 s->srv_addr = srv->addr;
1960 s->srv = srv;
willy tarreau0f7af912005-12-17 12:21:26 +01001961 }
willy tarreau1a3442d2006-03-24 21:03:20 +01001962 else if (s->proxy->options & PR_O_BALANCE_SH) {
1963 struct server *srv;
1964 int len;
1965
1966 if (s->cli_addr.ss_family == AF_INET)
1967 len = 4;
1968 else if (s->cli_addr.ss_family == AF_INET6)
1969 len = 16;
1970 else /* unknown IP family */
1971 return SN_ERR_INTERNAL;
1972
1973 srv = get_server_sh(s->proxy,
1974 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
1975 len);
1976 s->srv_addr = srv->addr;
1977 s->srv = srv;
1978 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001979 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01001980 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001981 }
willy tarreaua1598082005-12-17 13:08:06 +01001982 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001983 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001984 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001985 }
1986 else if (s->proxy->options & PR_O_TRANSP) {
1987 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01001988 socklen_t salen = sizeof(s->srv_addr);
1989
willy tarreau5cbea6f2005-12-17 12:48:26 +01001990 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1991 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001992 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001993 }
1994 }
willy tarreau0f7af912005-12-17 12:21:26 +01001995
willy tarreaua41a8b42005-12-17 14:02:24 +01001996 /* if this server remaps proxied ports, we'll use
1997 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001998 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001999 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002000 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01002001
willy tarreaub952e1d2005-12-18 01:31:20 +01002002 if (!(s->proxy->options & PR_O_TRANSP) ||
2003 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01002004 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2005 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
2006 }
2007
willy tarreau0f7af912005-12-17 12:21:26 +01002008 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002009 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002010
2011 if (errno == ENFILE)
2012 send_log(s->proxy, LOG_EMERG,
2013 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2014 s->proxy->id, maxfd);
2015 else if (errno == EMFILE)
2016 send_log(s->proxy, LOG_EMERG,
2017 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2018 s->proxy->id, maxfd);
2019 else if (errno == ENOBUFS || errno == ENOMEM)
2020 send_log(s->proxy, LOG_EMERG,
2021 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2022 s->proxy->id, maxfd);
2023 /* this is a resource error */
2024 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002025 }
2026
willy tarreau9fe663a2005-12-17 13:02:59 +01002027 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002028 /* do not log anything there, it's a normal condition when this option
2029 * is used to serialize connections to a server !
2030 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002031 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2032 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002033 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002034 }
2035
willy tarreau0f7af912005-12-17 12:21:26 +01002036 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2037 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002038 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002039 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002040 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002041 }
2042
willy tarreaub952e1d2005-12-18 01:31:20 +01002043 if (s->proxy->options & PR_O_TCP_SRV_KA)
2044 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2045
willy tarreau0174f312005-12-18 01:02:42 +01002046 /* allow specific binding :
2047 * - server-specific at first
2048 * - proxy-specific next
2049 */
2050 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2051 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2052 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2053 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2054 s->proxy->id, s->srv->id);
2055 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002056 send_log(s->proxy, LOG_EMERG,
2057 "Cannot bind to source address before connect() for server %s/%s.\n",
2058 s->proxy->id, s->srv->id);
2059 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002060 }
2061 }
2062 else if (s->proxy->options & PR_O_BIND_SRC) {
2063 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2064 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2065 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2066 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002067 send_log(s->proxy, LOG_EMERG,
2068 "Cannot bind to source address before connect() for server %s/%s.\n",
2069 s->proxy->id, s->srv->id);
2070 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002071 }
willy tarreaua1598082005-12-17 13:08:06 +01002072 }
2073
willy tarreaub1285d52005-12-18 01:20:14 +01002074 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2075 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2076
2077 if (errno == EAGAIN || errno == EADDRINUSE) {
2078 char *msg;
2079 if (errno == EAGAIN) /* no free ports left, try again later */
2080 msg = "no free ports";
2081 else
2082 msg = "local address already in use";
2083
2084 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002085 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002086 send_log(s->proxy, LOG_EMERG,
2087 "Connect() failed for server %s/%s: %s.\n",
2088 s->proxy->id, s->srv->id, msg);
2089 return SN_ERR_RESOURCE;
2090 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002091 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002092 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002093 return SN_ERR_SRVTO;
2094 } else {
2095 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002096 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002097 close(fd);
2098 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002099 }
2100 }
2101
willy tarreau5cbea6f2005-12-17 12:48:26 +01002102 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002103 fdtab[fd].read = &event_srv_read;
2104 fdtab[fd].write = &event_srv_write;
2105 fdtab[fd].state = FD_STCONN; /* connection in progress */
2106
2107 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002108#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2109 if (PrevReadEvent) {
2110 assert(!(FD_ISSET(fd, PrevReadEvent)));
2111 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2112 }
2113#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002114
2115 fd_insert(fd);
2116
2117 if (s->proxy->contimeout)
2118 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2119 else
2120 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002121 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002122}
2123
2124/*
2125 * this function is called on a read event from a client socket.
2126 * It returns 0.
2127 */
2128int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002129 struct task *t = fdtab[fd].owner;
2130 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002131 struct buffer *b = s->req;
2132 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002133
willy tarreau12350152005-12-18 01:03:27 +01002134#ifdef DEBUG_FULL
2135 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2136#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002137
willy tarreau0f7af912005-12-17 12:21:26 +01002138 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002139#ifdef FILL_BUFFERS
2140 while (1)
2141#else
2142 do
2143#endif
2144 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002145 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2146 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002147 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002148 }
2149 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002150 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002151 }
2152 else {
2153 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002154 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2155 * since it means that the rewrite protection has been removed. This
2156 * implies that the if statement can be removed.
2157 */
2158 if (max > b->rlim - b->data)
2159 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002160 }
2161
2162 if (max == 0) { /* not anymore room to store data */
2163 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002164 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002165 }
2166
willy tarreau3242e862005-12-17 12:27:53 +01002167#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002168 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002169 int skerr;
2170 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002171
willy tarreau5cbea6f2005-12-17 12:48:26 +01002172 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2173 if (skerr)
2174 ret = -1;
2175 else
2176 ret = recv(fd, b->r, max, 0);
2177 }
willy tarreau3242e862005-12-17 12:27:53 +01002178#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002179 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002180#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002181 if (ret > 0) {
2182 b->r += ret;
2183 b->l += ret;
2184 s->res_cr = RES_DATA;
2185
2186 if (b->r == b->data + BUFSIZE) {
2187 b->r = b->data; /* wrap around the buffer */
2188 }
willy tarreaua1598082005-12-17 13:08:06 +01002189
2190 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002191 /* we hope to read more data or to get a close on next round */
2192 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002193 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002194 else if (ret == 0) {
2195 s->res_cr = RES_NULL;
2196 break;
2197 }
2198 else if (errno == EAGAIN) {/* ignore EAGAIN */
2199 break;
2200 }
2201 else {
2202 s->res_cr = RES_ERROR;
2203 fdtab[fd].state = FD_STERROR;
2204 break;
2205 }
2206 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002207#ifndef FILL_BUFFERS
2208 while (0);
2209#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002210 }
2211 else {
2212 s->res_cr = RES_ERROR;
2213 fdtab[fd].state = FD_STERROR;
2214 }
2215
willy tarreau5cbea6f2005-12-17 12:48:26 +01002216 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002217 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002218 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2219 else
2220 tv_eternity(&s->crexpire);
2221
2222 task_wakeup(&rq, t);
2223 }
willy tarreau0f7af912005-12-17 12:21:26 +01002224
willy tarreau0f7af912005-12-17 12:21:26 +01002225 return 0;
2226}
2227
2228
2229/*
2230 * this function is called on a read event from a server socket.
2231 * It returns 0.
2232 */
2233int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002234 struct task *t = fdtab[fd].owner;
2235 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002236 struct buffer *b = s->rep;
2237 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002238
willy tarreau12350152005-12-18 01:03:27 +01002239#ifdef DEBUG_FULL
2240 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2241#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002242
willy tarreau0f7af912005-12-17 12:21:26 +01002243 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002244#ifdef FILL_BUFFERS
2245 while (1)
2246#else
2247 do
2248#endif
2249 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002250 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2251 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002252 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002253 }
2254 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002255 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002256 }
2257 else {
2258 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002259 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2260 * since it means that the rewrite protection has been removed. This
2261 * implies that the if statement can be removed.
2262 */
2263 if (max > b->rlim - b->data)
2264 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002265 }
2266
2267 if (max == 0) { /* not anymore room to store data */
2268 FD_CLR(fd, StaticReadEvent);
2269 break;
2270 }
2271
willy tarreau3242e862005-12-17 12:27:53 +01002272#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002273 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002274 int skerr;
2275 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002276
willy tarreau5cbea6f2005-12-17 12:48:26 +01002277 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2278 if (skerr)
2279 ret = -1;
2280 else
2281 ret = recv(fd, b->r, max, 0);
2282 }
willy tarreau3242e862005-12-17 12:27:53 +01002283#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002284 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002285#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002286 if (ret > 0) {
2287 b->r += ret;
2288 b->l += ret;
2289 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002290
willy tarreau5cbea6f2005-12-17 12:48:26 +01002291 if (b->r == b->data + BUFSIZE) {
2292 b->r = b->data; /* wrap around the buffer */
2293 }
willy tarreaua1598082005-12-17 13:08:06 +01002294
2295 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002296 /* we hope to read more data or to get a close on next round */
2297 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002298 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002299 else if (ret == 0) {
2300 s->res_sr = RES_NULL;
2301 break;
2302 }
2303 else if (errno == EAGAIN) {/* ignore EAGAIN */
2304 break;
2305 }
2306 else {
2307 s->res_sr = RES_ERROR;
2308 fdtab[fd].state = FD_STERROR;
2309 break;
2310 }
2311 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002312#ifndef FILL_BUFFERS
2313 while (0);
2314#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002315 }
2316 else {
2317 s->res_sr = RES_ERROR;
2318 fdtab[fd].state = FD_STERROR;
2319 }
2320
willy tarreau5cbea6f2005-12-17 12:48:26 +01002321 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002322 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002323 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2324 else
2325 tv_eternity(&s->srexpire);
2326
2327 task_wakeup(&rq, t);
2328 }
willy tarreau0f7af912005-12-17 12:21:26 +01002329
willy tarreau0f7af912005-12-17 12:21:26 +01002330 return 0;
2331}
2332
2333/*
2334 * this function is called on a write event from a client socket.
2335 * It returns 0.
2336 */
2337int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002338 struct task *t = fdtab[fd].owner;
2339 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002340 struct buffer *b = s->rep;
2341 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002342
willy tarreau12350152005-12-18 01:03:27 +01002343#ifdef DEBUG_FULL
2344 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2345#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002346
2347 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002348 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002349 // max = BUFSIZE; BUG !!!!
2350 max = 0;
2351 }
2352 else if (b->r > b->w) {
2353 max = b->r - b->w;
2354 }
2355 else
2356 max = b->data + BUFSIZE - b->w;
2357
willy tarreau0f7af912005-12-17 12:21:26 +01002358 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002359 if (max == 0) {
2360 s->res_cw = RES_NULL;
2361 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002362 tv_eternity(&s->cwexpire);
2363 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002364 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002365 }
2366
willy tarreau3242e862005-12-17 12:27:53 +01002367#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002368 {
2369 int skerr;
2370 socklen_t lskerr = sizeof(skerr);
2371
2372 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2373 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002374 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002375 else
willy tarreau3242e862005-12-17 12:27:53 +01002376 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002377 }
willy tarreau3242e862005-12-17 12:27:53 +01002378#else
willy tarreau0f7af912005-12-17 12:21:26 +01002379 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002380#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002381
2382 if (ret > 0) {
2383 b->l -= ret;
2384 b->w += ret;
2385
2386 s->res_cw = RES_DATA;
2387
2388 if (b->w == b->data + BUFSIZE) {
2389 b->w = b->data; /* wrap around the buffer */
2390 }
2391 }
2392 else if (ret == 0) {
2393 /* nothing written, just make as if we were never called */
2394// s->res_cw = RES_NULL;
2395 return 0;
2396 }
2397 else if (errno == EAGAIN) /* ignore EAGAIN */
2398 return 0;
2399 else {
2400 s->res_cw = RES_ERROR;
2401 fdtab[fd].state = FD_STERROR;
2402 }
2403 }
2404 else {
2405 s->res_cw = RES_ERROR;
2406 fdtab[fd].state = FD_STERROR;
2407 }
2408
willy tarreaub1ff9db2005-12-17 13:51:03 +01002409 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002410 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002411 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2412 s->crexpire = s->cwexpire;
2413 }
willy tarreau0f7af912005-12-17 12:21:26 +01002414 else
2415 tv_eternity(&s->cwexpire);
2416
willy tarreau5cbea6f2005-12-17 12:48:26 +01002417 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002418 return 0;
2419}
2420
2421
2422/*
2423 * this function is called on a write event from a server socket.
2424 * It returns 0.
2425 */
2426int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002427 struct task *t = fdtab[fd].owner;
2428 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002429 struct buffer *b = s->req;
2430 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002431
willy tarreau12350152005-12-18 01:03:27 +01002432#ifdef DEBUG_FULL
2433 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2434#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002435
2436 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002437 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002438 // max = BUFSIZE; BUG !!!!
2439 max = 0;
2440 }
2441 else if (b->r > b->w) {
2442 max = b->r - b->w;
2443 }
2444 else
2445 max = b->data + BUFSIZE - b->w;
2446
willy tarreau0f7af912005-12-17 12:21:26 +01002447 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002448 if (max == 0) {
2449 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002450 if (s->srv_state == SV_STCONN) {
2451 int skerr;
2452 socklen_t lskerr = sizeof(skerr);
2453 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2454 if (skerr) {
2455 s->res_sw = RES_ERROR;
2456 fdtab[fd].state = FD_STERROR;
2457 task_wakeup(&rq, t);
2458 tv_eternity(&s->swexpire);
2459 FD_CLR(fd, StaticWriteEvent);
2460 return 0;
2461 }
2462 }
2463
willy tarreau0f7af912005-12-17 12:21:26 +01002464 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002465 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002466 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002467 tv_eternity(&s->swexpire);
2468 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002469 return 0;
2470 }
2471
willy tarreau3242e862005-12-17 12:27:53 +01002472#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002473 {
2474 int skerr;
2475 socklen_t lskerr = sizeof(skerr);
2476 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2477 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002478 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002479 else
willy tarreau3242e862005-12-17 12:27:53 +01002480 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002481 }
willy tarreau3242e862005-12-17 12:27:53 +01002482#else
willy tarreau0f7af912005-12-17 12:21:26 +01002483 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002484#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002485 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002486 if (ret > 0) {
2487 b->l -= ret;
2488 b->w += ret;
2489
2490 s->res_sw = RES_DATA;
2491
2492 if (b->w == b->data + BUFSIZE) {
2493 b->w = b->data; /* wrap around the buffer */
2494 }
2495 }
2496 else if (ret == 0) {
2497 /* nothing written, just make as if we were never called */
2498 // s->res_sw = RES_NULL;
2499 return 0;
2500 }
2501 else if (errno == EAGAIN) /* ignore EAGAIN */
2502 return 0;
2503 else {
2504 s->res_sw = RES_ERROR;
2505 fdtab[fd].state = FD_STERROR;
2506 }
2507 }
2508 else {
2509 s->res_sw = RES_ERROR;
2510 fdtab[fd].state = FD_STERROR;
2511 }
2512
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002513 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2514 * otherwise it could loop indefinitely !
2515 */
2516 if (s->srv_state != SV_STCONN) {
2517 if (s->proxy->srvtimeout) {
2518 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
2519 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2520 s->srexpire = s->swexpire;
2521 }
2522 else
2523 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002524 }
willy tarreau0f7af912005-12-17 12:21:26 +01002525
willy tarreau5cbea6f2005-12-17 12:48:26 +01002526 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002527 return 0;
2528}
2529
2530
2531/*
willy tarreaue39cd132005-12-17 13:00:18 +01002532 * returns a message to the client ; the connection is shut down for read,
2533 * and the request is cleared so that no server connection can be initiated.
2534 * The client must be in a valid state for this (HEADER, DATA ...).
2535 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002536 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002537 */
2538void client_retnclose(struct session *s, int len, const char *msg) {
2539 FD_CLR(s->cli_fd, StaticReadEvent);
2540 FD_SET(s->cli_fd, StaticWriteEvent);
2541 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002542 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002543 shutdown(s->cli_fd, SHUT_RD);
2544 s->cli_state = CL_STSHUTR;
2545 strcpy(s->rep->data, msg);
2546 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002547 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002548 s->rep->r += len;
2549 s->req->l = 0;
2550}
2551
2552
2553/*
2554 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002555 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002556 */
2557void client_return(struct session *s, int len, const char *msg) {
2558 strcpy(s->rep->data, msg);
2559 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002560 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002561 s->rep->r += len;
2562 s->req->l = 0;
2563}
2564
willy tarreau9fe663a2005-12-17 13:02:59 +01002565/*
2566 * send a log for the session when we have enough info about it
2567 */
2568void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002569 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002570 struct proxy *p = s->proxy;
2571 int log;
2572 char *uri;
2573 char *pxid;
2574 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002575 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002576
2577 /* This is a first attempt at a better logging system.
2578 * For now, we rely on send_log() to provide the date, although it obviously
2579 * is the date of the log and not of the request, and most fields are not
2580 * computed.
2581 */
2582
willy tarreaua1598082005-12-17 13:08:06 +01002583 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002584
willy tarreau8a86dbf2005-12-18 00:45:59 +01002585 if (s->cli_addr.ss_family == AF_INET)
2586 inet_ntop(AF_INET,
2587 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2588 pn, sizeof(pn));
2589 else
2590 inet_ntop(AF_INET6,
2591 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2592 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002593
willy tarreauc1cae632005-12-17 14:12:23 +01002594 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002595 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002596 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002597
willy tarreauc1cae632005-12-17 14:12:23 +01002598 tm = localtime(&s->logs.tv_accept.tv_sec);
2599 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002600 char tmpline[MAX_SYSLOG_LEN], *h;
2601 int hdr;
2602
2603 h = tmpline;
2604 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2605 *(h++) = ' ';
2606 *(h++) = '{';
2607 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2608 if (hdr)
2609 *(h++) = '|';
2610 if (s->req_cap[hdr] != NULL)
2611 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2612 }
2613 *(h++) = '}';
2614 }
2615
2616 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2617 *(h++) = ' ';
2618 *(h++) = '{';
2619 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2620 if (hdr)
2621 *(h++) = '|';
2622 if (s->rsp_cap[hdr] != NULL)
2623 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2624 }
2625 *(h++) = '}';
2626 }
2627
2628 if (h < tmpline + sizeof(tmpline) - 4) {
2629 *(h++) = ' ';
2630 *(h++) = '"';
2631 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2632 *(h++) = '"';
2633 }
2634 *h = '\0';
2635
willy tarreau0fe39652005-12-18 01:25:24 +01002636 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%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002637 pn,
2638 (s->cli_addr.ss_family == AF_INET) ?
2639 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2640 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002641 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2642 tm->tm_hour, tm->tm_min, tm->tm_sec,
2643 pxid, srv,
2644 s->logs.t_request,
2645 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2646 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002647 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2648 s->logs.status,
2649 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002650 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2651 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002652 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2653 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2654 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2655 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau0fe39652005-12-18 01:25:24 +01002656 p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002657 }
2658 else {
willy tarreau0fe39652005-12-18 01:25:24 +01002659 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c %d/%d\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002660 pn,
2661 (s->cli_addr.ss_family == AF_INET) ?
2662 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2663 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002664 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2665 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002666 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002667 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002668 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2669 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002670 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002671 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2672 p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002673 }
2674
2675 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002676}
2677
willy tarreaue39cd132005-12-17 13:00:18 +01002678
2679/*
willy tarreau0f7af912005-12-17 12:21:26 +01002680 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002681 * to an accept. It tries to accept as many connections as possible.
2682 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002683 */
2684int event_accept(int fd) {
2685 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002686 struct session *s;
2687 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002688 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01002689 int max_accept;
2690
2691 if (global.nbproc > 1)
2692 max_accept = 8; /* let other processes catch some connections too */
2693 else
2694 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01002695
willy tarreauc2becdc2006-03-19 19:36:48 +01002696 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002697 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002698 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002699
willy tarreaub1285d52005-12-18 01:20:14 +01002700 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2701 switch (errno) {
2702 case EAGAIN:
2703 case EINTR:
2704 case ECONNABORTED:
2705 return 0; /* nothing more to accept */
2706 case ENFILE:
2707 send_log(p, LOG_EMERG,
2708 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2709 p->id, maxfd);
2710 return 0;
2711 case EMFILE:
2712 send_log(p, LOG_EMERG,
2713 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2714 p->id, maxfd);
2715 return 0;
2716 case ENOBUFS:
2717 case ENOMEM:
2718 send_log(p, LOG_EMERG,
2719 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2720 p->id, maxfd);
2721 return 0;
2722 default:
2723 return 0;
2724 }
2725 }
willy tarreau0f7af912005-12-17 12:21:26 +01002726
willy tarreau5cbea6f2005-12-17 12:48:26 +01002727 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2728 Alert("out of memory in event_accept().\n");
2729 FD_CLR(fd, StaticReadEvent);
2730 p->state = PR_STIDLE;
2731 close(cfd);
2732 return 0;
2733 }
willy tarreau0f7af912005-12-17 12:21:26 +01002734
willy tarreaub1285d52005-12-18 01:20:14 +01002735 /* if this session comes from a known monitoring system, we want to ignore
2736 * it as soon as possible, which means closing it immediately for TCP.
2737 */
2738 s->flags = 0;
2739 if (addr.ss_family == AF_INET &&
2740 p->mon_mask.s_addr &&
2741 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2742 if (p->mode == PR_MODE_TCP) {
2743 close(cfd);
2744 pool_free(session, s);
2745 continue;
2746 }
2747 s->flags |= SN_MONITOR;
2748 }
2749
willy tarreau5cbea6f2005-12-17 12:48:26 +01002750 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2751 Alert("out of memory in event_accept().\n");
2752 FD_CLR(fd, StaticReadEvent);
2753 p->state = PR_STIDLE;
2754 close(cfd);
2755 pool_free(session, s);
2756 return 0;
2757 }
willy tarreau0f7af912005-12-17 12:21:26 +01002758
willy tarreau5cbea6f2005-12-17 12:48:26 +01002759 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002760 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002761 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2762 close(cfd);
2763 pool_free(task, t);
2764 pool_free(session, s);
2765 return 0;
2766 }
willy tarreau0f7af912005-12-17 12:21:26 +01002767
willy tarreau5cbea6f2005-12-17 12:48:26 +01002768 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2769 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2770 (char *) &one, sizeof(one)) == -1)) {
2771 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2772 close(cfd);
2773 pool_free(task, t);
2774 pool_free(session, s);
2775 return 0;
2776 }
willy tarreau0f7af912005-12-17 12:21:26 +01002777
willy tarreaub952e1d2005-12-18 01:31:20 +01002778 if (p->options & PR_O_TCP_CLI_KA)
2779 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2780
willy tarreau9fe663a2005-12-17 13:02:59 +01002781 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2782 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2783 t->state = TASK_IDLE;
2784 t->process = process_session;
2785 t->context = s;
2786
2787 s->task = t;
2788 s->proxy = p;
2789 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2790 s->srv_state = SV_STIDLE;
2791 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002792
willy tarreau9fe663a2005-12-17 13:02:59 +01002793 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2794 s->cli_fd = cfd;
2795 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002796 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002797 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002798
willy tarreaub1285d52005-12-18 01:20:14 +01002799 if (s->flags & SN_MONITOR)
2800 s->logs.logwait = 0;
2801 else
2802 s->logs.logwait = p->to_log;
2803
willy tarreaua1598082005-12-17 13:08:06 +01002804 s->logs.tv_accept = now;
2805 s->logs.t_request = -1;
2806 s->logs.t_connect = -1;
2807 s->logs.t_data = -1;
2808 s->logs.t_close = 0;
2809 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002810 s->logs.cli_cookie = NULL;
2811 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002812 s->logs.status = -1;
2813 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002814
willy tarreau2f6ba652005-12-17 13:57:42 +01002815 s->uniq_id = totalconn;
2816
willy tarreau4302f492005-12-18 01:00:37 +01002817 if (p->nb_req_cap > 0) {
2818 if ((s->req_cap =
2819 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2820 == NULL) { /* no memory */
2821 close(cfd); /* nothing can be done for this fd without memory */
2822 pool_free(task, t);
2823 pool_free(session, s);
2824 return 0;
2825 }
2826 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2827 }
2828 else
2829 s->req_cap = NULL;
2830
2831 if (p->nb_rsp_cap > 0) {
2832 if ((s->rsp_cap =
2833 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2834 == NULL) { /* no memory */
2835 if (s->req_cap != NULL)
2836 pool_free_to(p->req_cap_pool, s->req_cap);
2837 close(cfd); /* nothing can be done for this fd without memory */
2838 pool_free(task, t);
2839 pool_free(session, s);
2840 return 0;
2841 }
2842 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2843 }
2844 else
2845 s->rsp_cap = NULL;
2846
willy tarreau5cbea6f2005-12-17 12:48:26 +01002847 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2848 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002849 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002850 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002851
willy tarreau8a86dbf2005-12-18 00:45:59 +01002852 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002853 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002854 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002855 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002856
willy tarreau9fe663a2005-12-17 13:02:59 +01002857 if (p->to_log) {
2858 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002859 if (s->logs.logwait & LW_CLIP)
2860 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002861 sess_log(s);
2862 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002863 else if (s->cli_addr.ss_family == AF_INET) {
2864 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2865 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2866 sn, sizeof(sn)) &&
2867 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2868 pn, sizeof(pn))) {
2869 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2870 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2871 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2872 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2873 }
2874 }
2875 else {
2876 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2877 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2878 sn, sizeof(sn)) &&
2879 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2880 pn, sizeof(pn))) {
2881 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2882 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2883 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2884 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2885 }
2886 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002887 }
willy tarreau0f7af912005-12-17 12:21:26 +01002888
willy tarreau982249e2005-12-18 00:57:06 +01002889 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002890 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002891 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002892 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002893 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002894 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002895 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002896 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002897
willy tarreau8a86dbf2005-12-18 00:45:59 +01002898 if (s->cli_addr.ss_family == AF_INET) {
2899 char pn[INET_ADDRSTRLEN];
2900 inet_ntop(AF_INET,
2901 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2902 pn, sizeof(pn));
2903
2904 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2905 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2906 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2907 }
2908 else {
2909 char pn[INET6_ADDRSTRLEN];
2910 inet_ntop(AF_INET6,
2911 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2912 pn, sizeof(pn));
2913
2914 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2915 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2916 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2917 }
2918
willy tarreauef900ab2005-12-17 12:52:52 +01002919 write(1, trash, len);
2920 }
willy tarreau0f7af912005-12-17 12:21:26 +01002921
willy tarreau5cbea6f2005-12-17 12:48:26 +01002922 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002923 if (s->rsp_cap != NULL)
2924 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2925 if (s->req_cap != NULL)
2926 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002927 close(cfd); /* nothing can be done for this fd without memory */
2928 pool_free(task, t);
2929 pool_free(session, s);
2930 return 0;
2931 }
willy tarreau4302f492005-12-18 01:00:37 +01002932
willy tarreau5cbea6f2005-12-17 12:48:26 +01002933 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002934 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002935 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2936 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002937 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002938 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002939
willy tarreau5cbea6f2005-12-17 12:48:26 +01002940 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2941 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002942 if (s->rsp_cap != NULL)
2943 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2944 if (s->req_cap != NULL)
2945 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002946 close(cfd); /* nothing can be done for this fd without memory */
2947 pool_free(task, t);
2948 pool_free(session, s);
2949 return 0;
2950 }
2951 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002952 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002953 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 +01002954
willy tarreau5cbea6f2005-12-17 12:48:26 +01002955 fdtab[cfd].read = &event_cli_read;
2956 fdtab[cfd].write = &event_cli_write;
2957 fdtab[cfd].owner = t;
2958 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002959
willy tarreaub1285d52005-12-18 01:20:14 +01002960 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2961 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2962 /* Either we got a request from a monitoring system on an HTTP instance,
2963 * or we're in health check mode with the 'httpchk' option enabled. In
2964 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2965 */
2966 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2967 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2968 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002969 }
2970 else {
2971 FD_SET(cfd, StaticReadEvent);
2972 }
2973
willy tarreaub952e1d2005-12-18 01:31:20 +01002974#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2975 if (PrevReadEvent) {
2976 assert(!(FD_ISSET(cfd, PrevReadEvent)));
2977 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
2978 }
2979#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002980 fd_insert(cfd);
2981
2982 tv_eternity(&s->cnexpire);
2983 tv_eternity(&s->srexpire);
2984 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01002985 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002986 tv_eternity(&s->cwexpire);
2987
willy tarreaub1285d52005-12-18 01:20:14 +01002988 if (s->proxy->clitimeout) {
2989 if (FD_ISSET(cfd, StaticReadEvent))
2990 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2991 if (FD_ISSET(cfd, StaticWriteEvent))
2992 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
2993 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002994
willy tarreaub1285d52005-12-18 01:20:14 +01002995 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002996
2997 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002998
2999 if (p->mode != PR_MODE_HEALTH)
3000 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003001
3002 p->nbconn++;
3003 actconn++;
3004 totalconn++;
3005
willy tarreaub952e1d2005-12-18 01:31:20 +01003006 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003007 } /* end of while (p->nbconn < p->maxconn) */
3008 return 0;
3009}
willy tarreau0f7af912005-12-17 12:21:26 +01003010
willy tarreau0f7af912005-12-17 12:21:26 +01003011
willy tarreau5cbea6f2005-12-17 12:48:26 +01003012/*
3013 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003014 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3015 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003016 * or -1 if an error occured.
3017 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003018int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003019 struct task *t = fdtab[fd].owner;
3020 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003021 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003022 socklen_t lskerr = sizeof(skerr);
3023
willy tarreau05be12b2006-03-19 19:35:00 +01003024 skerr = 1;
3025 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3026 || (skerr != 0)) {
3027 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003028 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003029 fdtab[fd].state = FD_STERROR;
3030 FD_CLR(fd, StaticWriteEvent);
3031 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003032 else if (s->result != -1) {
3033 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003034 if (s->proxy->options & PR_O_HTTP_CHK) {
3035 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003036 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003037 * so we'll send the request, and won't wake the checker up now.
3038 */
3039#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003040 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003041#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003042 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003043#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003044 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003045 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3046 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3047 return 0;
3048 }
willy tarreau05be12b2006-03-19 19:35:00 +01003049 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003050 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003051 FD_CLR(fd, StaticWriteEvent);
3052 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003053 }
3054 else {
3055 /* good TCP connection is enough */
3056 s->result = 1;
3057 }
3058 }
3059
3060 task_wakeup(&rq, t);
3061 return 0;
3062}
3063
willy tarreau0f7af912005-12-17 12:21:26 +01003064
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003065/*
3066 * This function is used only for server health-checks. It handles
3067 * the server's reply to an HTTP request. It returns 1 if the server replies
3068 * 2xx or 3xx (valid responses), or -1 in other cases.
3069 */
3070int event_srv_chk_r(int fd) {
3071 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003072 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003073 struct task *t = fdtab[fd].owner;
3074 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003075 int skerr;
3076 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003077
willy tarreaua4a583a2005-12-18 01:39:19 +01003078 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003079
willy tarreau05be12b2006-03-19 19:35:00 +01003080 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3081 if (!skerr) {
3082#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003083 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003084#else
willy tarreau05be12b2006-03-19 19:35:00 +01003085 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3086 * but the connection was closed on the remote end. Fortunately, recv still
3087 * works correctly and we don't need to do the getsockopt() on linux.
3088 */
3089 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003090#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003091
3092 if ((len >= sizeof("HTTP/1.0 000")) &&
3093 !memcmp(reply, "HTTP/1.", 7) &&
3094 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3095 result = 1;
3096 }
3097
3098 if (result == -1)
3099 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003100
3101 if (s->result != -1)
3102 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003103
3104 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003105 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003106 return 0;
3107}
3108
3109
3110/*
3111 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3112 * and moves <end> just after the end of <str>.
3113 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3114 * the shift value (positive or negative) is returned.
3115 * If there's no space left, the move is not done.
3116 *
3117 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003118int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003119 int delta;
3120 int len;
3121
3122 len = strlen(str);
3123 delta = len - (end - pos);
3124
3125 if (delta + b->r >= b->data + BUFSIZE)
3126 return 0; /* no space left */
3127
3128 /* first, protect the end of the buffer */
3129 memmove(end + delta, end, b->data + b->l - end);
3130
3131 /* now, copy str over pos */
3132 memcpy(pos, str,len);
3133
willy tarreau5cbea6f2005-12-17 12:48:26 +01003134 /* we only move data after the displaced zone */
3135 if (b->r > pos) b->r += delta;
3136 if (b->w > pos) b->w += delta;
3137 if (b->h > pos) b->h += delta;
3138 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003139 b->l += delta;
3140
3141 return delta;
3142}
3143
willy tarreau8337c6b2005-12-17 13:41:01 +01003144/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003145 * len is 0.
3146 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003147int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003148 int delta;
3149
3150 delta = len - (end - pos);
3151
3152 if (delta + b->r >= b->data + BUFSIZE)
3153 return 0; /* no space left */
3154
Willy TARREAUe78ae262006-01-08 01:24:12 +01003155 if (b->data + b->l < end)
3156 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3157 return 0;
3158
willy tarreau0f7af912005-12-17 12:21:26 +01003159 /* first, protect the end of the buffer */
3160 memmove(end + delta, end, b->data + b->l - end);
3161
3162 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003163 if (len)
3164 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003165
willy tarreau5cbea6f2005-12-17 12:48:26 +01003166 /* we only move data after the displaced zone */
3167 if (b->r > pos) b->r += delta;
3168 if (b->w > pos) b->w += delta;
3169 if (b->h > pos) b->h += delta;
3170 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003171 b->l += delta;
3172
3173 return delta;
3174}
3175
3176
3177int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3178 char *old_dst = dst;
3179
3180 while (*str) {
3181 if (*str == '\\') {
3182 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003183 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003184 int len, num;
3185
3186 num = *str - '0';
3187 str++;
3188
willy tarreau8a86dbf2005-12-18 00:45:59 +01003189 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003190 len = matches[num].rm_eo - matches[num].rm_so;
3191 memcpy(dst, src + matches[num].rm_so, len);
3192 dst += len;
3193 }
3194
3195 }
3196 else if (*str == 'x') {
3197 unsigned char hex1, hex2;
3198 str++;
3199
willy tarreauc1f47532005-12-18 01:08:26 +01003200 hex1 = toupper(*str++) - '0';
3201 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003202
3203 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3204 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3205 *dst++ = (hex1<<4) + hex2;
3206 }
3207 else
3208 *dst++ = *str++;
3209 }
3210 else
3211 *dst++ = *str++;
3212 }
3213 *dst = 0;
3214 return dst - old_dst;
3215}
3216
willy tarreauc1f47532005-12-18 01:08:26 +01003217static int ishex(char s)
3218{
3219 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3220}
3221
3222/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3223char *check_replace_string(char *str)
3224{
3225 char *err = NULL;
3226 while (*str) {
3227 if (*str == '\\') {
3228 err = str; /* in case of a backslash, we return the pointer to it */
3229 str++;
3230 if (!*str)
3231 return err;
3232 else if (isdigit((int)*str))
3233 err = NULL;
3234 else if (*str == 'x') {
3235 str++;
3236 if (!ishex(*str))
3237 return err;
3238 str++;
3239 if (!ishex(*str))
3240 return err;
3241 err = NULL;
3242 }
3243 else {
3244 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3245 err = NULL;
3246 }
3247 }
3248 str++;
3249 }
3250 return err;
3251}
3252
3253
willy tarreau9fe663a2005-12-17 13:02:59 +01003254
willy tarreau0f7af912005-12-17 12:21:26 +01003255/*
3256 * manages the client FSM and its socket. BTW, it also tries to handle the
3257 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3258 * 0 else.
3259 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003260int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003261 int s = t->srv_state;
3262 int c = t->cli_state;
3263 struct buffer *req = t->req;
3264 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003265 int method_checked = 0;
3266 appsess *asession_temp = NULL;
3267 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003268
willy tarreau750a4722005-12-17 13:21:24 +01003269#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003270 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3271 cli_stnames[c], srv_stnames[s],
3272 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3273 t->crexpire.tv_sec, t->crexpire.tv_usec,
3274 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003275#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003276 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3277 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3278 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3279 //);
3280 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003281 /* now parse the partial (or complete) headers */
3282 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3283 char *ptr;
3284 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003285 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003286
willy tarreau5cbea6f2005-12-17 12:48:26 +01003287 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003288
willy tarreau0f7af912005-12-17 12:21:26 +01003289 /* look for the end of the current header */
3290 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3291 ptr++;
3292
willy tarreau5cbea6f2005-12-17 12:48:26 +01003293 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003294 int line, len;
3295 /* we can only get here after an end of headers */
3296 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003297
willy tarreaue39cd132005-12-17 13:00:18 +01003298 if (t->flags & SN_CLDENY) {
3299 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003300 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003301 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003302 if (!(t->flags & SN_ERR_MASK))
3303 t->flags |= SN_ERR_PRXCOND;
3304 if (!(t->flags & SN_FINST_MASK))
3305 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003306 return 1;
3307 }
3308
willy tarreau5cbea6f2005-12-17 12:48:26 +01003309 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003310 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3311 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003312 }
willy tarreau0f7af912005-12-17 12:21:26 +01003313
willy tarreau9fe663a2005-12-17 13:02:59 +01003314 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003315 if (t->cli_addr.ss_family == AF_INET) {
3316 unsigned char *pn;
3317 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3318 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3319 pn[0], pn[1], pn[2], pn[3]);
3320 buffer_replace2(req, req->h, req->h, trash, len);
3321 }
3322 else if (t->cli_addr.ss_family == AF_INET6) {
3323 char pn[INET6_ADDRSTRLEN];
3324 inet_ntop(AF_INET6,
3325 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3326 pn, sizeof(pn));
3327 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3328 buffer_replace2(req, req->h, req->h, trash, len);
3329 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003330 }
3331
willy tarreau25c4ea52005-12-18 00:49:49 +01003332 /* add a "connection: close" line if needed */
3333 if (t->proxy->options & PR_O_HTTP_CLOSE)
3334 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3335
willy tarreau982249e2005-12-18 00:57:06 +01003336 if (!memcmp(req->data, "POST ", 5)) {
3337 /* this is a POST request, which is not cacheable by default */
3338 t->flags |= SN_POST;
3339 }
willy tarreaucd878942005-12-17 13:27:43 +01003340
willy tarreau5cbea6f2005-12-17 12:48:26 +01003341 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003342 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003343
willy tarreau750a4722005-12-17 13:21:24 +01003344 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003345 /* FIXME: we'll set the client in a wait state while we try to
3346 * connect to the server. Is this really needed ? wouldn't it be
3347 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003348 //FD_CLR(t->cli_fd, StaticReadEvent);
3349 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003350
3351 /* FIXME: if we break here (as up to 1.1.23), having the client
3352 * shutdown its connection can lead to an abort further.
3353 * it's better to either return 1 or even jump directly to the
3354 * data state which will save one schedule.
3355 */
3356 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003357
3358 if (!t->proxy->clitimeout ||
3359 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3360 /* If the client has no timeout, or if the server is not ready yet,
3361 * and we know for sure that it can expire, then it's cleaner to
3362 * disable the timeout on the client side so that too low values
3363 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003364 *
3365 * FIXME-20050705: the server needs a way to re-enable this time-out
3366 * when it switches its state, otherwise a client can stay connected
3367 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003368 */
3369 tv_eternity(&t->crexpire);
3370
willy tarreau197e8ec2005-12-17 14:10:59 +01003371 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003372 }
willy tarreau0f7af912005-12-17 12:21:26 +01003373
Willy TARREAU13032e72006-03-12 17:31:45 +01003374 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3375 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003376 /* this is a partial header, let's wait for more to come */
3377 req->lr = ptr;
3378 break;
3379 }
willy tarreau0f7af912005-12-17 12:21:26 +01003380
willy tarreau5cbea6f2005-12-17 12:48:26 +01003381 /* now we know that *ptr is either \r or \n,
3382 * and that there are at least 1 char after it.
3383 */
3384 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3385 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3386 else
3387 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003388
willy tarreau5cbea6f2005-12-17 12:48:26 +01003389 /*
3390 * now we know that we have a full header ; we can do whatever
3391 * we want with these pointers :
3392 * req->h = beginning of header
3393 * ptr = end of header (first \r or \n)
3394 * req->lr = beginning of next line (next rep->h)
3395 * req->r = end of data (not used at this stage)
3396 */
willy tarreau0f7af912005-12-17 12:21:26 +01003397
willy tarreau12350152005-12-18 01:03:27 +01003398 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3399 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3400 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3401
3402 /* skip ; */
3403 request_line++;
3404
3405 /* look if we have a jsessionid */
3406
3407 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3408
3409 /* skip jsessionid= */
3410 request_line += t->proxy->appsession_name_len + 1;
3411
3412 /* First try if we allready have an appsession */
3413 asession_temp = &local_asession;
3414
3415 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3416 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3417 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3418 return 0;
3419 }
3420
3421 /* Copy the sessionid */
3422 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3423 asession_temp->sessid[t->proxy->appsession_len] = 0;
3424 asession_temp->serverid = NULL;
3425
3426 /* only do insert, if lookup fails */
3427 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3428 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3429 Alert("Not enough memory process_cli():asession:calloc().\n");
3430 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3431 return 0;
3432 }
3433 asession_temp->sessid = local_asession.sessid;
3434 asession_temp->serverid = local_asession.serverid;
3435 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003436 } /* end if (chtbl_lookup()) */
3437 else {
willy tarreau12350152005-12-18 01:03:27 +01003438 /*free wasted memory;*/
3439 pool_free_to(apools.sessid, local_asession.sessid);
3440 }
3441
3442 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3443 asession_temp->request_count++;
3444
3445#if defined(DEBUG_HASH)
3446 print_table(&(t->proxy->htbl_proxy));
3447#endif
3448
3449 if (asession_temp->serverid == NULL) {
3450 Alert("Found Application Session without matching server.\n");
3451 } else {
3452 struct server *srv = t->proxy->srv;
3453 while (srv) {
3454 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3455 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3456 /* we found the server and it's usable */
3457 t->flags &= ~SN_CK_MASK;
3458 t->flags |= SN_CK_VALID | SN_DIRECT;
3459 t->srv = srv;
3460 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003461 } else {
willy tarreau12350152005-12-18 01:03:27 +01003462 t->flags &= ~SN_CK_MASK;
3463 t->flags |= SN_CK_DOWN;
3464 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003465 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003466 srv = srv->next;
3467 }/* end while(srv) */
3468 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003469 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003470 else {
3471 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3472 }
willy tarreau598da412005-12-18 01:07:29 +01003473 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003474 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003475 else{
3476 //printf("No Methode-Header with Session-String\n");
3477 }
3478
willy tarreau8337c6b2005-12-17 13:41:01 +01003479 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003480 /* we have a complete HTTP request that we must log */
3481 int urilen;
3482
willy tarreaua1598082005-12-17 13:08:06 +01003483 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003484 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003485 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003486 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003487 if (!(t->flags & SN_ERR_MASK))
3488 t->flags |= SN_ERR_PRXCOND;
3489 if (!(t->flags & SN_FINST_MASK))
3490 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003491 return 1;
3492 }
3493
3494 urilen = ptr - req->h;
3495 if (urilen >= REQURI_LEN)
3496 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003497 memcpy(t->logs.uri, req->h, urilen);
3498 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003499
willy tarreaua1598082005-12-17 13:08:06 +01003500 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003501 sess_log(t);
3502 }
willy tarreau4302f492005-12-18 01:00:37 +01003503 else if (t->logs.logwait & LW_REQHDR) {
3504 struct cap_hdr *h;
3505 int len;
3506 for (h = t->proxy->req_cap; h; h = h->next) {
3507 if ((h->namelen + 2 <= ptr - req->h) &&
3508 (req->h[h->namelen] == ':') &&
3509 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3510
3511 if (t->req_cap[h->index] == NULL)
3512 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3513
3514 len = ptr - (req->h + h->namelen + 2);
3515 if (len > h->len)
3516 len = h->len;
3517
3518 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3519 t->req_cap[h->index][len]=0;
3520 }
3521 }
3522
3523 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003524
willy tarreau5cbea6f2005-12-17 12:48:26 +01003525 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003526
willy tarreau982249e2005-12-18 00:57:06 +01003527 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003528 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003529 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 +01003530 max = ptr - req->h;
3531 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003532 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003533 trash[len++] = '\n';
3534 write(1, trash, len);
3535 }
willy tarreau0f7af912005-12-17 12:21:26 +01003536
willy tarreau25c4ea52005-12-18 00:49:49 +01003537
3538 /* remove "connection: " if needed */
3539 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3540 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3541 delete_header = 1;
3542 }
3543
willy tarreau5cbea6f2005-12-17 12:48:26 +01003544 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003545 if (!delete_header && t->proxy->req_exp != NULL
3546 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003547 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003548 char term;
3549
3550 term = *ptr;
3551 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003552 exp = t->proxy->req_exp;
3553 do {
3554 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3555 switch (exp->action) {
3556 case ACT_ALLOW:
3557 if (!(t->flags & SN_CLDENY))
3558 t->flags |= SN_CLALLOW;
3559 break;
3560 case ACT_REPLACE:
3561 if (!(t->flags & SN_CLDENY)) {
3562 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3563 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3564 }
3565 break;
3566 case ACT_REMOVE:
3567 if (!(t->flags & SN_CLDENY))
3568 delete_header = 1;
3569 break;
3570 case ACT_DENY:
3571 if (!(t->flags & SN_CLALLOW))
3572 t->flags |= SN_CLDENY;
3573 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003574 case ACT_PASS: /* we simply don't deny this one */
3575 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003576 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003577 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003578 }
willy tarreaue39cd132005-12-17 13:00:18 +01003579 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003580 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003581 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003582
willy tarreau240afa62005-12-17 13:14:35 +01003583 /* Now look for cookies. Conforming to RFC2109, we have to support
3584 * attributes whose name begin with a '$', and associate them with
3585 * the right cookie, if we want to delete this cookie.
3586 * So there are 3 cases for each cookie read :
3587 * 1) it's a special attribute, beginning with a '$' : ignore it.
3588 * 2) it's a server id cookie that we *MAY* want to delete : save
3589 * some pointers on it (last semi-colon, beginning of cookie...)
3590 * 3) it's an application cookie : we *MAY* have to delete a previous
3591 * "special" cookie.
3592 * At the end of loop, if a "special" cookie remains, we may have to
3593 * remove it. If no application cookie persists in the header, we
3594 * *MUST* delete it
3595 */
willy tarreau12350152005-12-18 01:03:27 +01003596 if (!delete_header &&
3597 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003598 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003599 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003600 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003601 char *del_colon, *del_cookie, *colon;
3602 int app_cookies;
3603
willy tarreau5cbea6f2005-12-17 12:48:26 +01003604 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003605 colon = p1;
3606 /* del_cookie == NULL => nothing to be deleted */
3607 del_colon = del_cookie = NULL;
3608 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003609
3610 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003611 /* skip spaces and colons, but keep an eye on these ones */
3612 while (p1 < ptr) {
3613 if (*p1 == ';' || *p1 == ',')
3614 colon = p1;
3615 else if (!isspace((int)*p1))
3616 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003617 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003618 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003619
3620 if (p1 == ptr)
3621 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003622
3623 /* p1 is at the beginning of the cookie name */
3624 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003625 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003626 p2++;
3627
3628 if (p2 == ptr)
3629 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003630
3631 p3 = p2 + 1; /* skips the '=' sign */
3632 if (p3 == ptr)
3633 break;
3634
willy tarreau240afa62005-12-17 13:14:35 +01003635 p4 = p3;
3636 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003637 p4++;
3638
3639 /* here, we have the cookie name between p1 and p2,
3640 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003641 * we can process it :
3642 *
3643 * Cookie: NAME=VALUE;
3644 * | || || |
3645 * | || || +--> p4
3646 * | || |+-------> p3
3647 * | || +--------> p2
3648 * | |+------------> p1
3649 * | +-------------> colon
3650 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003651 */
3652
willy tarreau240afa62005-12-17 13:14:35 +01003653 if (*p1 == '$') {
3654 /* skip this one */
3655 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003656 else {
3657 /* first, let's see if we want to capture it */
3658 if (t->proxy->capture_name != NULL &&
3659 t->logs.cli_cookie == NULL &&
3660 (p4 - p1 >= t->proxy->capture_namelen) &&
3661 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3662 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003663
willy tarreau8337c6b2005-12-17 13:41:01 +01003664 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3665 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003666 } else {
3667 if (log_len > t->proxy->capture_len)
3668 log_len = t->proxy->capture_len;
3669 memcpy(t->logs.cli_cookie, p1, log_len);
3670 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003671 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003672 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003673
3674 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3675 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3676 /* Cool... it's the right one */
3677 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003678 char *delim;
3679
3680 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3681 * have the server ID betweek p3 and delim, and the original cookie between
3682 * delim+1 and p4. Otherwise, delim==p4 :
3683 *
3684 * Cookie: NAME=SRV~VALUE;
3685 * | || || | |
3686 * | || || | +--> p4
3687 * | || || +--------> delim
3688 * | || |+-----------> p3
3689 * | || +------------> p2
3690 * | |+----------------> p1
3691 * | +-----------------> colon
3692 * +------------------------> req->h
3693 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003694
willy tarreau0174f312005-12-18 01:02:42 +01003695 if (t->proxy->options & PR_O_COOK_PFX) {
3696 for (delim = p3; delim < p4; delim++)
3697 if (*delim == COOKIE_DELIM)
3698 break;
3699 }
3700 else
3701 delim = p4;
3702
3703
3704 /* Here, we'll look for the first running server which supports the cookie.
3705 * This allows to share a same cookie between several servers, for example
3706 * to dedicate backup servers to specific servers only.
3707 */
3708 while (srv) {
3709 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3710 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3711 /* we found the server and it's usable */
3712 t->flags &= ~SN_CK_MASK;
3713 t->flags |= SN_CK_VALID | SN_DIRECT;
3714 t->srv = srv;
3715 break;
willy tarreau12350152005-12-18 01:03:27 +01003716 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003717 /* we found a server, but it's down */
3718 t->flags &= ~SN_CK_MASK;
3719 t->flags |= SN_CK_DOWN;
3720 }
3721 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003722 srv = srv->next;
3723 }
3724
willy tarreau0174f312005-12-18 01:02:42 +01003725 if (!srv && !(t->flags & SN_CK_DOWN)) {
3726 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003727 t->flags &= ~SN_CK_MASK;
3728 t->flags |= SN_CK_INVALID;
3729 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003730
willy tarreau0174f312005-12-18 01:02:42 +01003731 /* depending on the cookie mode, we may have to either :
3732 * - delete the complete cookie if we're in insert+indirect mode, so that
3733 * the server never sees it ;
3734 * - remove the server id from the cookie value, and tag the cookie as an
3735 * application cookie so that it does not get accidentely removed later,
3736 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003737 */
willy tarreau0174f312005-12-18 01:02:42 +01003738 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3739 buffer_replace2(req, p3, delim + 1, NULL, 0);
3740 p4 -= (delim + 1 - p3);
3741 ptr -= (delim + 1 - p3);
3742 del_cookie = del_colon = NULL;
3743 app_cookies++; /* protect the header from deletion */
3744 }
3745 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003746 (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 +01003747 del_cookie = p1;
3748 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003749 }
willy tarreau12350152005-12-18 01:03:27 +01003750 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003751 /* now we know that we must keep this cookie since it's
3752 * not ours. But if we wanted to delete our cookie
3753 * earlier, we cannot remove the complete header, but we
3754 * can remove the previous block itself.
3755 */
3756 app_cookies++;
3757
3758 if (del_cookie != NULL) {
3759 buffer_replace2(req, del_cookie, p1, NULL, 0);
3760 p4 -= (p1 - del_cookie);
3761 ptr -= (p1 - del_cookie);
3762 del_cookie = del_colon = NULL;
3763 }
willy tarreau240afa62005-12-17 13:14:35 +01003764 }
willy tarreau12350152005-12-18 01:03:27 +01003765
3766 if ((t->proxy->appsession_name != NULL) &&
3767 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3768 /* first, let's see if the cookie is our appcookie*/
3769
3770 /* Cool... it's the right one */
3771
3772 asession_temp = &local_asession;
3773
3774 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3775 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3776 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3777 return 0;
3778 }
3779
3780 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3781 asession_temp->sessid[t->proxy->appsession_len] = 0;
3782 asession_temp->serverid = NULL;
3783
3784 /* only do insert, if lookup fails */
3785 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3786 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3787 Alert("Not enough memory process_cli():asession:calloc().\n");
3788 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3789 return 0;
3790 }
3791
3792 asession_temp->sessid = local_asession.sessid;
3793 asession_temp->serverid = local_asession.serverid;
3794 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3795 }
3796 else{
3797 /* free wasted memory */
3798 pool_free_to(apools.sessid, local_asession.sessid);
3799 }
3800
3801 if (asession_temp->serverid == NULL) {
3802 Alert("Found Application Session without matching server.\n");
3803 } else {
3804 struct server *srv = t->proxy->srv;
3805 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003806 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003807 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3808 /* we found the server and it's usable */
3809 t->flags &= ~SN_CK_MASK;
3810 t->flags |= SN_CK_VALID | SN_DIRECT;
3811 t->srv = srv;
3812 break;
3813 } else {
3814 t->flags &= ~SN_CK_MASK;
3815 t->flags |= SN_CK_DOWN;
3816 }
3817 }
3818 srv = srv->next;
3819 }/* end while(srv) */
3820 }/* end else if server == NULL */
3821
3822 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003823 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003824 }
willy tarreau240afa62005-12-17 13:14:35 +01003825
willy tarreau5cbea6f2005-12-17 12:48:26 +01003826 /* we'll have to look for another cookie ... */
3827 p1 = p4;
3828 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003829
3830 /* There's no more cookie on this line.
3831 * We may have marked the last one(s) for deletion.
3832 * We must do this now in two ways :
3833 * - if there is no app cookie, we simply delete the header ;
3834 * - if there are app cookies, we must delete the end of the
3835 * string properly, including the colon/semi-colon before
3836 * the cookie name.
3837 */
3838 if (del_cookie != NULL) {
3839 if (app_cookies) {
3840 buffer_replace2(req, del_colon, ptr, NULL, 0);
3841 /* WARNING! <ptr> becomes invalid for now. If some code
3842 * below needs to rely on it before the end of the global
3843 * header loop, we need to correct it with this code :
3844 * ptr = del_colon;
3845 */
3846 }
3847 else
3848 delete_header = 1;
3849 }
3850 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003851
3852 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003853 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003854 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003855 }
willy tarreau240afa62005-12-17 13:14:35 +01003856 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3857
willy tarreau5cbea6f2005-12-17 12:48:26 +01003858 req->h = req->lr;
3859 } /* while (req->lr < req->r) */
3860
3861 /* end of header processing (even if incomplete) */
3862
willy tarreauef900ab2005-12-17 12:52:52 +01003863 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3864 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3865 * full. We cannot loop here since event_cli_read will disable it only if
3866 * req->l == rlim-data
3867 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003868 FD_SET(t->cli_fd, StaticReadEvent);
3869 if (t->proxy->clitimeout)
3870 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3871 else
3872 tv_eternity(&t->crexpire);
3873 }
3874
willy tarreaue39cd132005-12-17 13:00:18 +01003875 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003876 * won't be able to free more later, so the session will never terminate.
3877 */
willy tarreaue39cd132005-12-17 13:00:18 +01003878 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003879 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003880 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003881 if (!(t->flags & SN_ERR_MASK))
3882 t->flags |= SN_ERR_PRXCOND;
3883 if (!(t->flags & SN_FINST_MASK))
3884 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003885 return 1;
3886 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003887 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003888 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003889 tv_eternity(&t->crexpire);
3890 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003891 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003892 if (!(t->flags & SN_ERR_MASK))
3893 t->flags |= SN_ERR_CLICL;
3894 if (!(t->flags & SN_FINST_MASK))
3895 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003896 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003897 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003898 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3899
3900 /* read timeout : give up with an error message.
3901 */
3902 t->logs.status = 408;
3903 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003904 if (!(t->flags & SN_ERR_MASK))
3905 t->flags |= SN_ERR_CLITO;
3906 if (!(t->flags & SN_FINST_MASK))
3907 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003908 return 1;
3909 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003910
3911 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003912 }
3913 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003914 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003915 /* FIXME: this error handling is partly buggy because we always report
3916 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3917 * or HEADER phase. BTW, it's not logical to expire the client while
3918 * we're waiting for the server to connect.
3919 */
willy tarreau0f7af912005-12-17 12:21:26 +01003920 /* read or write error */
3921 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003922 tv_eternity(&t->crexpire);
3923 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003924 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003925 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003926 if (!(t->flags & SN_ERR_MASK))
3927 t->flags |= SN_ERR_CLICL;
3928 if (!(t->flags & SN_FINST_MASK))
3929 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003930 return 1;
3931 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003932 /* last read, or end of server write */
3933 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003934 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003935 tv_eternity(&t->crexpire);
3936 shutdown(t->cli_fd, SHUT_RD);
3937 t->cli_state = CL_STSHUTR;
3938 return 1;
3939 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003940 /* last server read and buffer empty */
3941 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003942 FD_CLR(t->cli_fd, StaticWriteEvent);
3943 tv_eternity(&t->cwexpire);
3944 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003945 /* We must ensure that the read part is still alive when switching
3946 * to shutw */
3947 FD_SET(t->cli_fd, StaticReadEvent);
3948 if (t->proxy->clitimeout)
3949 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003950 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003951 //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 +01003952 return 1;
3953 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003954 /* read timeout */
3955 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3956 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003957 tv_eternity(&t->crexpire);
3958 shutdown(t->cli_fd, SHUT_RD);
3959 t->cli_state = CL_STSHUTR;
3960 if (!(t->flags & SN_ERR_MASK))
3961 t->flags |= SN_ERR_CLITO;
3962 if (!(t->flags & SN_FINST_MASK))
3963 t->flags |= SN_FINST_D;
3964 return 1;
3965 }
3966 /* write timeout */
3967 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3968 FD_CLR(t->cli_fd, StaticWriteEvent);
3969 tv_eternity(&t->cwexpire);
3970 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003971 /* We must ensure that the read part is still alive when switching
3972 * to shutw */
3973 FD_SET(t->cli_fd, StaticReadEvent);
3974 if (t->proxy->clitimeout)
3975 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3976
willy tarreau036e1ce2005-12-17 13:46:33 +01003977 t->cli_state = CL_STSHUTW;
3978 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003979 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003980 if (!(t->flags & SN_FINST_MASK))
3981 t->flags |= SN_FINST_D;
3982 return 1;
3983 }
willy tarreau0f7af912005-12-17 12:21:26 +01003984
willy tarreauc58fc692005-12-17 14:13:08 +01003985 if (req->l >= req->rlim - req->data) {
3986 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003987 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003988 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003989 FD_CLR(t->cli_fd, StaticReadEvent);
3990 tv_eternity(&t->crexpire);
3991 }
3992 }
3993 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003994 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003995 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3996 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003997 if (!t->proxy->clitimeout ||
3998 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3999 /* If the client has no timeout, or if the server not ready yet, and we
4000 * know for sure that it can expire, then it's cleaner to disable the
4001 * timeout on the client side so that too low values cannot make the
4002 * sessions abort too early.
4003 */
willy tarreau0f7af912005-12-17 12:21:26 +01004004 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004005 else
4006 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004007 }
4008 }
4009
4010 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004011 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004012 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4013 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4014 tv_eternity(&t->cwexpire);
4015 }
4016 }
4017 else { /* buffer not empty */
4018 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4019 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004020 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004021 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004022 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4023 t->crexpire = t->cwexpire;
4024 }
willy tarreau0f7af912005-12-17 12:21:26 +01004025 else
4026 tv_eternity(&t->cwexpire);
4027 }
4028 }
4029 return 0; /* other cases change nothing */
4030 }
4031 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004032 if (t->res_cw == RES_ERROR) {
4033 tv_eternity(&t->cwexpire);
4034 fd_delete(t->cli_fd);
4035 t->cli_state = CL_STCLOSE;
4036 if (!(t->flags & SN_ERR_MASK))
4037 t->flags |= SN_ERR_CLICL;
4038 if (!(t->flags & SN_FINST_MASK))
4039 t->flags |= SN_FINST_D;
4040 return 1;
4041 }
4042 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004043 tv_eternity(&t->cwexpire);
4044 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004045 t->cli_state = CL_STCLOSE;
4046 return 1;
4047 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004048 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4049 tv_eternity(&t->cwexpire);
4050 fd_delete(t->cli_fd);
4051 t->cli_state = CL_STCLOSE;
4052 if (!(t->flags & SN_ERR_MASK))
4053 t->flags |= SN_ERR_CLITO;
4054 if (!(t->flags & SN_FINST_MASK))
4055 t->flags |= SN_FINST_D;
4056 return 1;
4057 }
willy tarreau0f7af912005-12-17 12:21:26 +01004058 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004059 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004060 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4061 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4062 tv_eternity(&t->cwexpire);
4063 }
4064 }
4065 else { /* buffer not empty */
4066 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4067 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004068 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004069 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004070 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4071 t->crexpire = t->cwexpire;
4072 }
willy tarreau0f7af912005-12-17 12:21:26 +01004073 else
4074 tv_eternity(&t->cwexpire);
4075 }
4076 }
4077 return 0;
4078 }
4079 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004080 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004081 tv_eternity(&t->crexpire);
4082 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004083 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004084 if (!(t->flags & SN_ERR_MASK))
4085 t->flags |= SN_ERR_CLICL;
4086 if (!(t->flags & SN_FINST_MASK))
4087 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004088 return 1;
4089 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004090 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4091 tv_eternity(&t->crexpire);
4092 fd_delete(t->cli_fd);
4093 t->cli_state = CL_STCLOSE;
4094 return 1;
4095 }
4096 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4097 tv_eternity(&t->crexpire);
4098 fd_delete(t->cli_fd);
4099 t->cli_state = CL_STCLOSE;
4100 if (!(t->flags & SN_ERR_MASK))
4101 t->flags |= SN_ERR_CLITO;
4102 if (!(t->flags & SN_FINST_MASK))
4103 t->flags |= SN_FINST_D;
4104 return 1;
4105 }
willy tarreauef900ab2005-12-17 12:52:52 +01004106 else if (req->l >= req->rlim - req->data) {
4107 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004108
4109 /* FIXME-20050705: is it possible for a client to maintain a session
4110 * after the timeout by sending more data after it receives a close ?
4111 */
4112
willy tarreau0f7af912005-12-17 12:21:26 +01004113 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004114 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004115 FD_CLR(t->cli_fd, StaticReadEvent);
4116 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004117 //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 +01004118 }
4119 }
4120 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004121 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004122 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4123 FD_SET(t->cli_fd, StaticReadEvent);
4124 if (t->proxy->clitimeout)
4125 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4126 else
4127 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004128 //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 +01004129 }
4130 }
4131 return 0;
4132 }
4133 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004134 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004135 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004136 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 +01004137 write(1, trash, len);
4138 }
4139 return 0;
4140 }
4141 return 0;
4142}
4143
4144
4145/*
4146 * manages the server FSM and its socket. It returns 1 if a state has changed
4147 * (and a resync may be needed), 0 else.
4148 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004149int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004150 int s = t->srv_state;
4151 int c = t->cli_state;
4152 struct buffer *req = t->req;
4153 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004154 appsess *asession_temp = NULL;
4155 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004156 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004157
willy tarreau750a4722005-12-17 13:21:24 +01004158#ifdef DEBUG_FULL
4159 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4160#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004161 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4162 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4163 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4164 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004165 if (s == SV_STIDLE) {
4166 if (c == CL_STHEADERS)
4167 return 0; /* stay in idle, waiting for data to reach the client side */
4168 else if (c == CL_STCLOSE ||
4169 c == CL_STSHUTW ||
4170 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4171 tv_eternity(&t->cnexpire);
4172 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004173 if (!(t->flags & SN_ERR_MASK))
4174 t->flags |= SN_ERR_CLICL;
4175 if (!(t->flags & SN_FINST_MASK))
4176 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004177 return 1;
4178 }
4179 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01004180 /* initiate a connection to the server */
4181 conn_err = connect_server(t);
4182 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004183 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4184 t->srv_state = SV_STCONN;
4185 }
4186 else { /* try again */
4187 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004188 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004189 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004190 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004191 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4192 t->flags &= ~SN_CK_MASK;
4193 t->flags |= SN_CK_DOWN;
4194 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004195 }
4196
willy tarreaub1285d52005-12-18 01:20:14 +01004197 conn_err = connect_server(t);
4198 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004199 t->srv_state = SV_STCONN;
4200 break;
4201 }
4202 }
4203 if (t->conn_retries < 0) {
4204 /* if conn_retries < 0 or other error, let's abort */
4205 tv_eternity(&t->cnexpire);
4206 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004207 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004208 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004209 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004210 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004211 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004212 if (!(t->flags & SN_FINST_MASK))
4213 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004214 }
4215 }
4216 return 1;
4217 }
4218 }
4219 else if (s == SV_STCONN) { /* connection in progress */
4220 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004221 //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 +01004222 return 0; /* nothing changed */
4223 }
4224 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4225 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4226 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004227 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004228 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004229 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004230 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004231 if (t->conn_retries >= 0) {
4232 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004233 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004234 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004235 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4236 t->flags &= ~SN_CK_MASK;
4237 t->flags |= SN_CK_DOWN;
4238 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004239 }
willy tarreaub1285d52005-12-18 01:20:14 +01004240 conn_err = connect_server(t);
4241 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004242 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004243 }
willy tarreaub1285d52005-12-18 01:20:14 +01004244 else if (t->res_sw == RES_SILENT)
4245 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4246 else
4247 conn_err = SN_ERR_SRVCL; // it was a connect error.
4248
willy tarreau0f7af912005-12-17 12:21:26 +01004249 /* if conn_retries < 0 or other error, let's abort */
4250 tv_eternity(&t->cnexpire);
4251 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004252 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004253 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004254 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004255 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004256 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004257 if (!(t->flags & SN_FINST_MASK))
4258 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004259 return 1;
4260 }
4261 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004262 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004263
willy tarreau0f7af912005-12-17 12:21:26 +01004264 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004265 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004266 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004267 tv_eternity(&t->swexpire);
4268 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004269 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004270 if (t->proxy->srvtimeout) {
4271 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4272 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4273 t->srexpire = t->swexpire;
4274 }
4275 else
4276 tv_eternity(&t->swexpire);
4277 }
willy tarreau0f7af912005-12-17 12:21:26 +01004278
4279 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4280 FD_SET(t->srv_fd, StaticReadEvent);
4281 if (t->proxy->srvtimeout)
4282 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4283 else
4284 tv_eternity(&t->srexpire);
4285
4286 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004287 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004288
4289 /* if the user wants to log as soon as possible, without counting
4290 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004291 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004292 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4293 sess_log(t);
4294 }
willy tarreau0f7af912005-12-17 12:21:26 +01004295 }
willy tarreauef900ab2005-12-17 12:52:52 +01004296 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004297 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004298 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4299 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004300 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004301 return 1;
4302 }
4303 }
4304 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004305 /* now parse the partial (or complete) headers */
4306 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4307 char *ptr;
4308 int delete_header;
4309
4310 ptr = rep->lr;
4311
4312 /* look for the end of the current header */
4313 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4314 ptr++;
4315
4316 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004317 int line, len;
4318
4319 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004320
4321 /* first, we'll block if security checks have caught nasty things */
4322 if (t->flags & SN_CACHEABLE) {
4323 if ((t->flags & SN_CACHE_COOK) &&
4324 (t->flags & SN_SCK_ANY) &&
4325 (t->proxy->options & PR_O_CHK_CACHE)) {
4326
4327 /* we're in presence of a cacheable response containing
4328 * a set-cookie header. We'll block it as requested by
4329 * the 'checkcache' option, and send an alert.
4330 */
4331 tv_eternity(&t->srexpire);
4332 tv_eternity(&t->swexpire);
4333 fd_delete(t->srv_fd);
4334 t->srv_state = SV_STCLOSE;
4335 t->logs.status = 502;
4336 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4337 if (!(t->flags & SN_ERR_MASK))
4338 t->flags |= SN_ERR_PRXCOND;
4339 if (!(t->flags & SN_FINST_MASK))
4340 t->flags |= SN_FINST_H;
4341
4342 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4343 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4344
4345 return 1;
4346 }
4347 }
4348
willy tarreau982249e2005-12-18 00:57:06 +01004349 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4350 if (t->flags & SN_SVDENY) {
4351 tv_eternity(&t->srexpire);
4352 tv_eternity(&t->swexpire);
4353 fd_delete(t->srv_fd);
4354 t->srv_state = SV_STCLOSE;
4355 t->logs.status = 502;
4356 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4357 if (!(t->flags & SN_ERR_MASK))
4358 t->flags |= SN_ERR_PRXCOND;
4359 if (!(t->flags & SN_FINST_MASK))
4360 t->flags |= SN_FINST_H;
4361 return 1;
4362 }
4363
willy tarreau5cbea6f2005-12-17 12:48:26 +01004364 /* we'll have something else to do here : add new headers ... */
4365
willy tarreaucd878942005-12-17 13:27:43 +01004366 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4367 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004368 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004369 * insert a set-cookie here, except if we want to insert only on POST
4370 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004371 */
willy tarreau750a4722005-12-17 13:21:24 +01004372 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004373 t->proxy->cookie_name,
4374 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004375
willy tarreau036e1ce2005-12-17 13:46:33 +01004376 t->flags |= SN_SCK_INSERTED;
4377
willy tarreau750a4722005-12-17 13:21:24 +01004378 /* Here, we will tell an eventual cache on the client side that we don't
4379 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4380 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4381 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4382 */
willy tarreau240afa62005-12-17 13:14:35 +01004383 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004384 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4385 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004386
4387 if (rep->data + rep->l < rep->h)
4388 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4389 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004390 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004391 }
4392
4393 /* headers to be added */
4394 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004395 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4396 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004397 }
4398
willy tarreau25c4ea52005-12-18 00:49:49 +01004399 /* add a "connection: close" line if needed */
4400 if (t->proxy->options & PR_O_HTTP_CLOSE)
4401 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4402
willy tarreau5cbea6f2005-12-17 12:48:26 +01004403 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004404 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004405 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004406
Willy TARREAU767ba712006-03-01 22:40:50 +01004407 /* client connection already closed or option 'httpclose' required :
4408 * we close the server's outgoing connection right now.
4409 */
4410 if ((req->l == 0) &&
4411 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4412 FD_CLR(t->srv_fd, StaticWriteEvent);
4413 tv_eternity(&t->swexpire);
4414
4415 /* We must ensure that the read part is still alive when switching
4416 * to shutw */
4417 FD_SET(t->srv_fd, StaticReadEvent);
4418 if (t->proxy->srvtimeout)
4419 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4420
4421 shutdown(t->srv_fd, SHUT_WR);
4422 t->srv_state = SV_STSHUTW;
4423 }
4424
willy tarreau25c4ea52005-12-18 00:49:49 +01004425 /* if the user wants to log as soon as possible, without counting
4426 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004427 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004428 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4429 t->logs.bytes = rep->h - rep->data;
4430 sess_log(t);
4431 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004432 break;
4433 }
4434
4435 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4436 if (ptr > rep->r - 2) {
4437 /* this is a partial header, let's wait for more to come */
4438 rep->lr = ptr;
4439 break;
4440 }
4441
4442 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4443 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4444
4445 /* now we know that *ptr is either \r or \n,
4446 * and that there are at least 1 char after it.
4447 */
4448 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4449 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4450 else
4451 rep->lr = ptr + 2; /* \r\n or \n\r */
4452
4453 /*
4454 * now we know that we have a full header ; we can do whatever
4455 * we want with these pointers :
4456 * rep->h = beginning of header
4457 * ptr = end of header (first \r or \n)
4458 * rep->lr = beginning of next line (next rep->h)
4459 * rep->r = end of data (not used at this stage)
4460 */
4461
willy tarreaua1598082005-12-17 13:08:06 +01004462
willy tarreau982249e2005-12-18 00:57:06 +01004463 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004464 t->logs.logwait &= ~LW_RESP;
4465 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004466 switch (t->logs.status) {
4467 case 200:
4468 case 203:
4469 case 206:
4470 case 300:
4471 case 301:
4472 case 410:
4473 /* RFC2616 @13.4:
4474 * "A response received with a status code of
4475 * 200, 203, 206, 300, 301 or 410 MAY be stored
4476 * by a cache (...) unless a cache-control
4477 * directive prohibits caching."
4478 *
4479 * RFC2616 @9.5: POST method :
4480 * "Responses to this method are not cacheable,
4481 * unless the response includes appropriate
4482 * Cache-Control or Expires header fields."
4483 */
4484 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4485 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4486 break;
4487 default:
4488 break;
4489 }
willy tarreau4302f492005-12-18 01:00:37 +01004490 }
4491 else if (t->logs.logwait & LW_RSPHDR) {
4492 struct cap_hdr *h;
4493 int len;
4494 for (h = t->proxy->rsp_cap; h; h = h->next) {
4495 if ((h->namelen + 2 <= ptr - rep->h) &&
4496 (rep->h[h->namelen] == ':') &&
4497 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4498
4499 if (t->rsp_cap[h->index] == NULL)
4500 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4501
4502 len = ptr - (rep->h + h->namelen + 2);
4503 if (len > h->len)
4504 len = h->len;
4505
4506 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4507 t->rsp_cap[h->index][len]=0;
4508 }
4509 }
4510
willy tarreaua1598082005-12-17 13:08:06 +01004511 }
4512
willy tarreau5cbea6f2005-12-17 12:48:26 +01004513 delete_header = 0;
4514
willy tarreau982249e2005-12-18 00:57:06 +01004515 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004516 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004517 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 +01004518 max = ptr - rep->h;
4519 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004520 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004521 trash[len++] = '\n';
4522 write(1, trash, len);
4523 }
4524
willy tarreau25c4ea52005-12-18 00:49:49 +01004525 /* remove "connection: " if needed */
4526 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4527 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4528 delete_header = 1;
4529 }
4530
willy tarreau5cbea6f2005-12-17 12:48:26 +01004531 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004532 if (!delete_header && t->proxy->rsp_exp != NULL
4533 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004534 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004535 char term;
4536
4537 term = *ptr;
4538 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004539 exp = t->proxy->rsp_exp;
4540 do {
4541 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4542 switch (exp->action) {
4543 case ACT_ALLOW:
4544 if (!(t->flags & SN_SVDENY))
4545 t->flags |= SN_SVALLOW;
4546 break;
4547 case ACT_REPLACE:
4548 if (!(t->flags & SN_SVDENY)) {
4549 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4550 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4551 }
4552 break;
4553 case ACT_REMOVE:
4554 if (!(t->flags & SN_SVDENY))
4555 delete_header = 1;
4556 break;
4557 case ACT_DENY:
4558 if (!(t->flags & SN_SVALLOW))
4559 t->flags |= SN_SVDENY;
4560 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004561 case ACT_PASS: /* we simply don't deny this one */
4562 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004563 }
4564 break;
4565 }
willy tarreaue39cd132005-12-17 13:00:18 +01004566 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004567 *ptr = term; /* restore the string terminator */
4568 }
4569
willy tarreau97f58572005-12-18 00:53:44 +01004570 /* check for cache-control: or pragma: headers */
4571 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4572 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4573 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4574 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4575 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004576 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004577 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4578 else {
4579 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004580 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004581 t->flags &= ~SN_CACHE_COOK;
4582 }
4583 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004584 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004585 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004586 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004587 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4588 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004589 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004590 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004591 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4592 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4593 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4594 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4595 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4596 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004597 }
4598 }
4599 }
4600
willy tarreau5cbea6f2005-12-17 12:48:26 +01004601 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004602 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004603 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004604 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004605 char *p1, *p2, *p3, *p4;
4606
willy tarreau97f58572005-12-18 00:53:44 +01004607 t->flags |= SN_SCK_ANY;
4608
willy tarreau5cbea6f2005-12-17 12:48:26 +01004609 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4610
4611 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004612 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004613 p1++;
4614
4615 if (p1 == ptr || *p1 == ';') /* end of cookie */
4616 break;
4617
4618 /* p1 is at the beginning of the cookie name */
4619 p2 = p1;
4620
4621 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4622 p2++;
4623
4624 if (p2 == ptr || *p2 == ';') /* next cookie */
4625 break;
4626
4627 p3 = p2 + 1; /* skips the '=' sign */
4628 if (p3 == ptr)
4629 break;
4630
4631 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004632 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004633 p4++;
4634
4635 /* here, we have the cookie name between p1 and p2,
4636 * and its value between p3 and p4.
4637 * we can process it.
4638 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004639
4640 /* first, let's see if we want to capture it */
4641 if (t->proxy->capture_name != NULL &&
4642 t->logs.srv_cookie == NULL &&
4643 (p4 - p1 >= t->proxy->capture_namelen) &&
4644 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4645 int log_len = p4 - p1;
4646
4647 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4648 Alert("HTTP logging : out of memory.\n");
4649 }
4650
4651 if (log_len > t->proxy->capture_len)
4652 log_len = t->proxy->capture_len;
4653 memcpy(t->logs.srv_cookie, p1, log_len);
4654 t->logs.srv_cookie[log_len] = 0;
4655 }
4656
4657 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4658 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004659 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004660 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004661
4662 /* If the cookie is in insert mode on a known server, we'll delete
4663 * this occurrence because we'll insert another one later.
4664 * We'll delete it too if the "indirect" option is set and we're in
4665 * a direct access. */
4666 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004667 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004668 /* this header must be deleted */
4669 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004670 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004671 }
4672 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4673 /* replace bytes p3->p4 with the cookie name associated
4674 * with this server since we know it.
4675 */
4676 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004677 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004678 }
willy tarreau0174f312005-12-18 01:02:42 +01004679 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4680 /* insert the cookie name associated with this server
4681 * before existing cookie, and insert a delimitor between them..
4682 */
4683 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4684 p3[t->srv->cklen] = COOKIE_DELIM;
4685 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4686 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004687 break;
4688 }
willy tarreau12350152005-12-18 01:03:27 +01004689
4690 /* first, let's see if the cookie is our appcookie*/
4691 if ((t->proxy->appsession_name != NULL) &&
4692 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4693
4694 /* Cool... it's the right one */
4695
willy tarreaub952e1d2005-12-18 01:31:20 +01004696 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004697 asession_temp = &local_asession;
4698
willy tarreaub952e1d2005-12-18 01:31:20 +01004699 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004700 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4701 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4702 }
4703 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4704 asession_temp->sessid[t->proxy->appsession_len] = 0;
4705 asession_temp->serverid = NULL;
4706
4707 /* only do insert, if lookup fails */
4708 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4709 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4710 Alert("Not enought Memory process_srv():asession:calloc().\n");
4711 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4712 return 0;
4713 }
4714 asession_temp->sessid = local_asession.sessid;
4715 asession_temp->serverid = local_asession.serverid;
4716 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004717 }/* end if (chtbl_lookup()) */
4718 else {
willy tarreau12350152005-12-18 01:03:27 +01004719 /* free wasted memory */
4720 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004721 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004722
willy tarreaub952e1d2005-12-18 01:31:20 +01004723 if (asession_temp->serverid == NULL) {
4724 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004725 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4726 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4727 }
4728 asession_temp->serverid[0] = '\0';
4729 }
4730
willy tarreaub952e1d2005-12-18 01:31:20 +01004731 if (asession_temp->serverid[0] == '\0')
4732 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004733
4734 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4735
4736#if defined(DEBUG_HASH)
4737 print_table(&(t->proxy->htbl_proxy));
4738#endif
4739 break;
4740 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004741 else {
4742 // fprintf(stderr,"Ignoring unknown cookie : ");
4743 // write(2, p1, p2-p1);
4744 // fprintf(stderr," = ");
4745 // write(2, p3, p4-p3);
4746 // fprintf(stderr,"\n");
4747 }
4748 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4749 } /* we're now at the end of the cookie value */
4750 } /* end of cookie processing */
4751
willy tarreau97f58572005-12-18 00:53:44 +01004752 /* check for any set-cookie in case we check for cacheability */
4753 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4754 (t->proxy->options & PR_O_CHK_CACHE) &&
4755 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4756 t->flags |= SN_SCK_ANY;
4757 }
4758
willy tarreau5cbea6f2005-12-17 12:48:26 +01004759 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004760 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004761 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004762
willy tarreau5cbea6f2005-12-17 12:48:26 +01004763 rep->h = rep->lr;
4764 } /* while (rep->lr < rep->r) */
4765
4766 /* end of header processing (even if incomplete) */
4767
willy tarreauef900ab2005-12-17 12:52:52 +01004768 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4769 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4770 * full. We cannot loop here since event_srv_read will disable it only if
4771 * rep->l == rlim-data
4772 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004773 FD_SET(t->srv_fd, StaticReadEvent);
4774 if (t->proxy->srvtimeout)
4775 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4776 else
4777 tv_eternity(&t->srexpire);
4778 }
willy tarreau0f7af912005-12-17 12:21:26 +01004779
willy tarreau8337c6b2005-12-17 13:41:01 +01004780 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004781 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004782 tv_eternity(&t->srexpire);
4783 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004784 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004785 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004786 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004787 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004788 if (!(t->flags & SN_ERR_MASK))
4789 t->flags |= SN_ERR_SRVCL;
4790 if (!(t->flags & SN_FINST_MASK))
4791 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004792 return 1;
4793 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004794 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004795 * since we are in header mode, if there's no space left for headers, we
4796 * won't be able to free more later, so the session will never terminate.
4797 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004798 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 +01004799 FD_CLR(t->srv_fd, StaticReadEvent);
4800 tv_eternity(&t->srexpire);
4801 shutdown(t->srv_fd, SHUT_RD);
4802 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004803 //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 +01004804 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004805 }
4806 /* read timeout : return a 504 to the client.
4807 */
4808 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4809 tv_eternity(&t->srexpire);
4810 tv_eternity(&t->swexpire);
4811 fd_delete(t->srv_fd);
4812 t->srv_state = SV_STCLOSE;
4813 t->logs.status = 504;
4814 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004815 if (!(t->flags & SN_ERR_MASK))
4816 t->flags |= SN_ERR_SRVTO;
4817 if (!(t->flags & SN_FINST_MASK))
4818 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004819 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004820
4821 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004822 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004823 /* FIXME!!! here, we don't want to switch to SHUTW if the
4824 * client shuts read too early, because we may still have
4825 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004826 * The side-effect is that if the client completely closes its
4827 * connection during SV_STHEADER, the connection to the server
4828 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004829 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004830 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004831 FD_CLR(t->srv_fd, StaticWriteEvent);
4832 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004833
4834 /* We must ensure that the read part is still alive when switching
4835 * to shutw */
4836 FD_SET(t->srv_fd, StaticReadEvent);
4837 if (t->proxy->srvtimeout)
4838 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4839
willy tarreau0f7af912005-12-17 12:21:26 +01004840 shutdown(t->srv_fd, SHUT_WR);
4841 t->srv_state = SV_STSHUTW;
4842 return 1;
4843 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004844 /* write timeout */
4845 /* FIXME!!! here, we don't want to switch to SHUTW if the
4846 * client shuts read too early, because we may still have
4847 * some work to do on the headers.
4848 */
4849 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4850 FD_CLR(t->srv_fd, StaticWriteEvent);
4851 tv_eternity(&t->swexpire);
4852 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004853 /* We must ensure that the read part is still alive when switching
4854 * to shutw */
4855 FD_SET(t->srv_fd, StaticReadEvent);
4856 if (t->proxy->srvtimeout)
4857 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4858
4859 /* We must ensure that the read part is still alive when switching
4860 * to shutw */
4861 FD_SET(t->srv_fd, StaticReadEvent);
4862 if (t->proxy->srvtimeout)
4863 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4864
willy tarreau036e1ce2005-12-17 13:46:33 +01004865 t->srv_state = SV_STSHUTW;
4866 if (!(t->flags & SN_ERR_MASK))
4867 t->flags |= SN_ERR_SRVTO;
4868 if (!(t->flags & SN_FINST_MASK))
4869 t->flags |= SN_FINST_H;
4870 return 1;
4871 }
willy tarreau0f7af912005-12-17 12:21:26 +01004872
4873 if (req->l == 0) {
4874 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4875 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4876 tv_eternity(&t->swexpire);
4877 }
4878 }
4879 else { /* client buffer not empty */
4880 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4881 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004882 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004883 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004884 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4885 t->srexpire = t->swexpire;
4886 }
willy tarreau0f7af912005-12-17 12:21:26 +01004887 else
4888 tv_eternity(&t->swexpire);
4889 }
4890 }
4891
willy tarreau5cbea6f2005-12-17 12:48:26 +01004892 /* be nice with the client side which would like to send a complete header
4893 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4894 * would read all remaining data at once ! The client should not write past rep->lr
4895 * when the server is in header state.
4896 */
4897 //return header_processed;
4898 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004899 }
4900 else if (s == SV_STDATA) {
4901 /* read or write error */
4902 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004903 tv_eternity(&t->srexpire);
4904 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004905 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004906 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004907 if (!(t->flags & SN_ERR_MASK))
4908 t->flags |= SN_ERR_SRVCL;
4909 if (!(t->flags & SN_FINST_MASK))
4910 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004911 return 1;
4912 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004913 /* last read, or end of client write */
4914 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004915 FD_CLR(t->srv_fd, StaticReadEvent);
4916 tv_eternity(&t->srexpire);
4917 shutdown(t->srv_fd, SHUT_RD);
4918 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004919 //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 +01004920 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004921 }
4922 /* end of client read and no more data to send */
4923 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4924 FD_CLR(t->srv_fd, StaticWriteEvent);
4925 tv_eternity(&t->swexpire);
4926 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004927 /* We must ensure that the read part is still alive when switching
4928 * to shutw */
4929 FD_SET(t->srv_fd, StaticReadEvent);
4930 if (t->proxy->srvtimeout)
4931 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4932
willy tarreaua41a8b42005-12-17 14:02:24 +01004933 t->srv_state = SV_STSHUTW;
4934 return 1;
4935 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004936 /* read timeout */
4937 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4938 FD_CLR(t->srv_fd, StaticReadEvent);
4939 tv_eternity(&t->srexpire);
4940 shutdown(t->srv_fd, SHUT_RD);
4941 t->srv_state = SV_STSHUTR;
4942 if (!(t->flags & SN_ERR_MASK))
4943 t->flags |= SN_ERR_SRVTO;
4944 if (!(t->flags & SN_FINST_MASK))
4945 t->flags |= SN_FINST_D;
4946 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004947 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004948 /* write timeout */
4949 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004950 FD_CLR(t->srv_fd, StaticWriteEvent);
4951 tv_eternity(&t->swexpire);
4952 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004953 /* We must ensure that the read part is still alive when switching
4954 * to shutw */
4955 FD_SET(t->srv_fd, StaticReadEvent);
4956 if (t->proxy->srvtimeout)
4957 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004958 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004959 if (!(t->flags & SN_ERR_MASK))
4960 t->flags |= SN_ERR_SRVTO;
4961 if (!(t->flags & SN_FINST_MASK))
4962 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004963 return 1;
4964 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004965
4966 /* recompute request time-outs */
4967 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004968 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4969 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4970 tv_eternity(&t->swexpire);
4971 }
4972 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004973 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004974 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4975 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004976 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004977 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004978 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4979 t->srexpire = t->swexpire;
4980 }
willy tarreau0f7af912005-12-17 12:21:26 +01004981 else
4982 tv_eternity(&t->swexpire);
4983 }
4984 }
4985
willy tarreaub1ff9db2005-12-17 13:51:03 +01004986 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004987 if (rep->l == BUFSIZE) { /* no room to read more data */
4988 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4989 FD_CLR(t->srv_fd, StaticReadEvent);
4990 tv_eternity(&t->srexpire);
4991 }
4992 }
4993 else {
4994 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4995 FD_SET(t->srv_fd, StaticReadEvent);
4996 if (t->proxy->srvtimeout)
4997 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4998 else
4999 tv_eternity(&t->srexpire);
5000 }
5001 }
5002
5003 return 0; /* other cases change nothing */
5004 }
5005 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005006 if (t->res_sw == RES_ERROR) {
5007 //FD_CLR(t->srv_fd, StaticWriteEvent);
5008 tv_eternity(&t->swexpire);
5009 fd_delete(t->srv_fd);
5010 //close(t->srv_fd);
5011 t->srv_state = SV_STCLOSE;
5012 if (!(t->flags & SN_ERR_MASK))
5013 t->flags |= SN_ERR_SRVCL;
5014 if (!(t->flags & SN_FINST_MASK))
5015 t->flags |= SN_FINST_D;
5016 return 1;
5017 }
5018 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005019 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005020 tv_eternity(&t->swexpire);
5021 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005022 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005023 t->srv_state = SV_STCLOSE;
5024 return 1;
5025 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005026 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5027 //FD_CLR(t->srv_fd, StaticWriteEvent);
5028 tv_eternity(&t->swexpire);
5029 fd_delete(t->srv_fd);
5030 //close(t->srv_fd);
5031 t->srv_state = SV_STCLOSE;
5032 if (!(t->flags & SN_ERR_MASK))
5033 t->flags |= SN_ERR_SRVTO;
5034 if (!(t->flags & SN_FINST_MASK))
5035 t->flags |= SN_FINST_D;
5036 return 1;
5037 }
willy tarreau0f7af912005-12-17 12:21:26 +01005038 else if (req->l == 0) {
5039 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5040 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5041 tv_eternity(&t->swexpire);
5042 }
5043 }
5044 else { /* buffer not empty */
5045 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5046 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005047 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005048 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005049 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5050 t->srexpire = t->swexpire;
5051 }
willy tarreau0f7af912005-12-17 12:21:26 +01005052 else
5053 tv_eternity(&t->swexpire);
5054 }
5055 }
5056 return 0;
5057 }
5058 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005059 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005060 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005061 tv_eternity(&t->srexpire);
5062 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005063 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005064 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005065 if (!(t->flags & SN_ERR_MASK))
5066 t->flags |= SN_ERR_SRVCL;
5067 if (!(t->flags & SN_FINST_MASK))
5068 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005069 return 1;
5070 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005071 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5072 //FD_CLR(t->srv_fd, StaticReadEvent);
5073 tv_eternity(&t->srexpire);
5074 fd_delete(t->srv_fd);
5075 //close(t->srv_fd);
5076 t->srv_state = SV_STCLOSE;
5077 return 1;
5078 }
5079 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5080 //FD_CLR(t->srv_fd, StaticReadEvent);
5081 tv_eternity(&t->srexpire);
5082 fd_delete(t->srv_fd);
5083 //close(t->srv_fd);
5084 t->srv_state = SV_STCLOSE;
5085 if (!(t->flags & SN_ERR_MASK))
5086 t->flags |= SN_ERR_SRVTO;
5087 if (!(t->flags & SN_FINST_MASK))
5088 t->flags |= SN_FINST_D;
5089 return 1;
5090 }
willy tarreau0f7af912005-12-17 12:21:26 +01005091 else if (rep->l == BUFSIZE) { /* no room to read more data */
5092 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5093 FD_CLR(t->srv_fd, StaticReadEvent);
5094 tv_eternity(&t->srexpire);
5095 }
5096 }
5097 else {
5098 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5099 FD_SET(t->srv_fd, StaticReadEvent);
5100 if (t->proxy->srvtimeout)
5101 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5102 else
5103 tv_eternity(&t->srexpire);
5104 }
5105 }
5106 return 0;
5107 }
5108 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005109 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005110 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005111 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 +01005112 write(1, trash, len);
5113 }
5114 return 0;
5115 }
5116 return 0;
5117}
5118
5119
willy tarreau5cbea6f2005-12-17 12:48:26 +01005120/* Processes the client and server jobs of a session task, then
5121 * puts it back to the wait queue in a clean state, or
5122 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005123 * the time the task accepts to wait, or TIME_ETERNITY for
5124 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005125 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005126int process_session(struct task *t) {
5127 struct session *s = t->context;
5128 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005129
willy tarreau5cbea6f2005-12-17 12:48:26 +01005130 do {
5131 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005132 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005133 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005134 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005135 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005136 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005137 } while (fsm_resync);
5138
5139 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005140 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005141 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005142
willy tarreau5cbea6f2005-12-17 12:48:26 +01005143 tv_min(&min1, &s->crexpire, &s->cwexpire);
5144 tv_min(&min2, &s->srexpire, &s->swexpire);
5145 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005146 tv_min(&t->expire, &min1, &min2);
5147
5148 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005149 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005150
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005151#ifdef DEBUG_FULL
5152 /* DEBUG code : this should never ever happen, otherwise it indicates
5153 * that a task still has something to do and will provoke a quick loop.
5154 */
5155 if (tv_remain2(&now, &t->expire) <= 0)
5156 exit(100);
5157#endif
5158
willy tarreaub952e1d2005-12-18 01:31:20 +01005159 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005160 }
5161
willy tarreau5cbea6f2005-12-17 12:48:26 +01005162 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005163 actconn--;
5164
willy tarreau982249e2005-12-18 00:57:06 +01005165 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005166 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005167 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 +01005168 write(1, trash, len);
5169 }
5170
willy tarreau750a4722005-12-17 13:21:24 +01005171 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005172 if (s->rep != NULL)
5173 s->logs.bytes = s->rep->total;
5174
willy tarreau9fe663a2005-12-17 13:02:59 +01005175 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005176 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005177 sess_log(s);
5178
willy tarreau0f7af912005-12-17 12:21:26 +01005179 /* the task MUST not be in the run queue anymore */
5180 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005181 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005182 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005183 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005184}
5185
5186
5187
5188/*
5189 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005190 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005191 */
5192int process_chk(struct task *t) {
5193 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005194 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005195 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005196
willy tarreauef900ab2005-12-17 12:52:52 +01005197 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005198
willy tarreau25424f82006-03-19 19:37:48 +01005199 new_chk:
5200 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005201 if (fd < 0) { /* no check currently running */
5202 //fprintf(stderr, "process_chk: 2\n");
5203 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5204 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005205 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005206 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005207
5208 /* we don't send any health-checks when the proxy is stopped or when
5209 * the server should not be checked.
5210 */
5211 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005212 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5213 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005214 task_queue(t); /* restore t to its place in the task list */
5215 return tv_remain2(&now, &t->expire);
5216 }
5217
willy tarreau5cbea6f2005-12-17 12:48:26 +01005218 /* we'll initiate a new check */
5219 s->result = 0; /* no result yet */
5220 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005221 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005222 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5223 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5224 //fprintf(stderr, "process_chk: 3\n");
5225
willy tarreaua41a8b42005-12-17 14:02:24 +01005226 /* we'll connect to the check port on the server */
5227 sa = s->addr;
5228 sa.sin_port = htons(s->check_port);
5229
willy tarreau0174f312005-12-18 01:02:42 +01005230 /* allow specific binding :
5231 * - server-specific at first
5232 * - proxy-specific next
5233 */
5234 if (s->state & SRV_BIND_SRC) {
5235 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5236 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5237 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5238 s->proxy->id, s->id);
5239 s->result = -1;
5240 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005241 }
willy tarreau0174f312005-12-18 01:02:42 +01005242 else if (s->proxy->options & PR_O_BIND_SRC) {
5243 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5244 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5245 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5246 s->proxy->id);
5247 s->result = -1;
5248 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005249 }
willy tarreau0174f312005-12-18 01:02:42 +01005250
5251 if (!s->result) {
5252 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5253 /* OK, connection in progress or established */
5254
5255 //fprintf(stderr, "process_chk: 4\n");
5256
5257 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5258 fdtab[fd].owner = t;
5259 fdtab[fd].read = &event_srv_chk_r;
5260 fdtab[fd].write = &event_srv_chk_w;
5261 fdtab[fd].state = FD_STCONN; /* connection in progress */
5262 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005263#ifdef DEBUG_FULL
5264 assert (!FD_ISSET(fd, StaticReadEvent));
5265#endif
willy tarreau0174f312005-12-18 01:02:42 +01005266 fd_insert(fd);
5267 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5268 tv_delayfrom(&t->expire, &now, s->inter);
5269 task_queue(t); /* restore t to its place in the task list */
5270 return tv_remain(&now, &t->expire);
5271 }
5272 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5273 s->result = -1; /* a real error */
5274 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005275 }
5276 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005277 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005278 }
5279
5280 if (!s->result) { /* nothing done */
5281 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005282 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5283 tv_delayfrom(&t->expire, &t->expire, s->inter);
5284 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005285 }
5286
5287 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005288 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005289 s->health--; /* still good */
5290 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005291 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005292 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005293 recount_servers(s->proxy);
5294 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5295 s->state & SRV_BACKUP ? "Backup " : "",
5296 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5297 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5298 send_log(s->proxy, LOG_ALERT,
5299 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5300 s->state & SRV_BACKUP ? "Backup " : "",
5301 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5302 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreauef900ab2005-12-17 12:52:52 +01005303
willy tarreau62084d42006-03-24 18:57:41 +01005304 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
willy tarreaudd07e972005-12-18 00:48:48 +01005305 Alert("Proxy %s has no server available !\n", s->proxy->id);
5306 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5307 }
5308 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005309 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005310 }
5311
5312 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005313 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005314 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5315 tv_delayfrom(&t->expire, &t->expire, s->inter);
5316 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005317 }
5318 else {
5319 //fprintf(stderr, "process_chk: 8\n");
5320 /* there was a test running */
5321 if (s->result > 0) { /* good server detected */
5322 //fprintf(stderr, "process_chk: 9\n");
5323 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005324 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005325 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005326 recount_servers(s->proxy);
5327 Warning("%sServer %s/%s UP. %d active and %d backup servers online.%s\n",
5328 s->state & SRV_BACKUP ? "Backup " : "",
5329 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5330 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5331 send_log(s->proxy, LOG_NOTICE,
5332 "%sServer %s/%s is UP. %d active and %d backup servers online.%s\n",
5333 s->state & SRV_BACKUP ? "Backup " : "",
5334 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5335 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreau535ae7a2005-12-17 12:58:00 +01005336 }
willy tarreauef900ab2005-12-17 12:52:52 +01005337
willy tarreaue47c8d72005-12-17 12:55:52 +01005338 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005339 s->state |= SRV_RUNNING;
5340 }
willy tarreauef900ab2005-12-17 12:52:52 +01005341 s->curfd = -1; /* no check running anymore */
5342 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005343 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005344 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5345 tv_delayfrom(&t->expire, &t->expire, s->inter);
5346 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005347 }
5348 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5349 //fprintf(stderr, "process_chk: 10\n");
5350 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005351 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005352 s->health--; /* still good */
5353 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005354 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005355
willy tarreau62084d42006-03-24 18:57:41 +01005356 if (s->health == s->rise) {
5357 recount_servers(s->proxy);
5358 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5359 s->state & SRV_BACKUP ? "Backup " : "",
5360 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5361 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5362 send_log(s->proxy, LOG_ALERT,
5363 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5364 s->state & SRV_BACKUP ? "Backup " : "",
5365 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5366 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5367
5368 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5369 Alert("Proxy %s has no server available !\n", s->proxy->id);
5370 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5371 }
5372 }
willy tarreauef900ab2005-12-17 12:52:52 +01005373
willy tarreau5cbea6f2005-12-17 12:48:26 +01005374 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005375 }
5376 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005377 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005378 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005379 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5380 tv_delayfrom(&t->expire, &t->expire, s->inter);
5381 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005382 }
5383 /* if result is 0 and there's no timeout, we have to wait again */
5384 }
5385 //fprintf(stderr, "process_chk: 11\n");
5386 s->result = 0;
5387 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005388 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005389}
5390
5391
willy tarreau5cbea6f2005-12-17 12:48:26 +01005392
willy tarreau0f7af912005-12-17 12:21:26 +01005393#if STATTIME > 0
5394int stats(void);
5395#endif
5396
5397/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005398 * This does 4 things :
5399 * - wake up all expired tasks
5400 * - call all runnable tasks
5401 * - call maintain_proxies() to enable/disable the listeners
5402 * - return the delay till next event in ms, -1 = wait indefinitely
5403 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5404 *
willy tarreau0f7af912005-12-17 12:21:26 +01005405 */
5406
willy tarreau1c2ad212005-12-18 01:11:29 +01005407int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005408 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005409 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005410 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005411
willy tarreaub952e1d2005-12-18 01:31:20 +01005412 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005413
willy tarreau1c2ad212005-12-18 01:11:29 +01005414 /* look for expired tasks and add them to the run queue.
5415 */
5416 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5417 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5418 tnext = t->next;
5419 if (t->state & TASK_RUNNING)
5420 continue;
5421
willy tarreaub952e1d2005-12-18 01:31:20 +01005422 if (tv_iseternity(&t->expire))
5423 continue;
5424
willy tarreau1c2ad212005-12-18 01:11:29 +01005425 /* wakeup expired entries. It doesn't matter if they are
5426 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005427 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005428 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005429 task_wakeup(&rq, t);
5430 }
5431 else {
5432 /* first non-runnable task. Use its expiration date as an upper bound */
5433 int temp_time = tv_remain(&now, &t->expire);
5434 if (temp_time)
5435 next_time = temp_time;
5436 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005437 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005438 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005439
willy tarreau1c2ad212005-12-18 01:11:29 +01005440 /* process each task in the run queue now. Each task may be deleted
5441 * since we only use tnext.
5442 */
5443 tnext = rq;
5444 while ((t = tnext) != NULL) {
5445 int temp_time;
5446
5447 tnext = t->rqnext;
5448 task_sleep(&rq, t);
5449 temp_time = t->process(t);
5450 next_time = MINTIME(temp_time, next_time);
5451 }
5452
5453 /* maintain all proxies in a consistent state. This should quickly become a task */
5454 time2 = maintain_proxies();
5455 return MINTIME(time2, next_time);
5456}
5457
5458
5459#if defined(ENABLE_EPOLL)
5460
5461/*
5462 * Main epoll() loop.
5463 */
5464
5465/* does 3 actions :
5466 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5467 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5468 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5469 *
5470 * returns 0 if initialization failed, !0 otherwise.
5471 */
5472
5473int epoll_loop(int action) {
5474 int next_time;
5475 int status;
5476 int fd;
5477
5478 int fds, count;
5479 int pr, pw, sr, sw;
5480 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5481 struct epoll_event ev;
5482
5483 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005484 static struct epoll_event *epoll_events = NULL;
5485 static int epoll_fd;
5486
5487 if (action == POLL_LOOP_ACTION_INIT) {
5488 epoll_fd = epoll_create(global.maxsock + 1);
5489 if (epoll_fd < 0)
5490 return 0;
5491 else {
5492 epoll_events = (struct epoll_event*)
5493 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5494 PrevReadEvent = (fd_set *)
5495 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5496 PrevWriteEvent = (fd_set *)
5497 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005498 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005499 return 1;
5500 }
5501 else if (action == POLL_LOOP_ACTION_CLEAN) {
5502 if (PrevWriteEvent) free(PrevWriteEvent);
5503 if (PrevReadEvent) free(PrevReadEvent);
5504 if (epoll_events) free(epoll_events);
5505 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005506 epoll_fd = 0;
5507 return 1;
5508 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005509
willy tarreau1c2ad212005-12-18 01:11:29 +01005510 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005511
willy tarreau1c2ad212005-12-18 01:11:29 +01005512 tv_now(&now);
5513
5514 while (1) {
5515 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005516
5517 /* stop when there's no connection left and we don't allow them anymore */
5518 if (!actconn && listeners == 0)
5519 break;
5520
willy tarreau0f7af912005-12-17 12:21:26 +01005521#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005522 {
5523 int time2;
5524 time2 = stats();
5525 next_time = MINTIME(time2, next_time);
5526 }
willy tarreau0f7af912005-12-17 12:21:26 +01005527#endif
5528
willy tarreau1c2ad212005-12-18 01:11:29 +01005529 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5530
5531 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5532 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5533
5534 if ((ro^rn) | (wo^wn)) {
5535 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5536#define FDSETS_ARE_INT_ALIGNED
5537#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005538
willy tarreauad90a0c2005-12-18 01:09:15 +01005539#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5540#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005541 pr = (ro >> count) & 1;
5542 pw = (wo >> count) & 1;
5543 sr = (rn >> count) & 1;
5544 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005545#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005546 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5547 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5548 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5549 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005550#endif
5551#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005552 pr = FD_ISSET(fd, PrevReadEvent);
5553 pw = FD_ISSET(fd, PrevWriteEvent);
5554 sr = FD_ISSET(fd, StaticReadEvent);
5555 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005556#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005557 if (!((sr^pr) | (sw^pw)))
5558 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005559
willy tarreau1c2ad212005-12-18 01:11:29 +01005560 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5561 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005562
willy tarreaub952e1d2005-12-18 01:31:20 +01005563#ifdef EPOLL_CTL_MOD_WORKAROUND
5564 /* I encountered a rarely reproducible problem with
5565 * EPOLL_CTL_MOD where a modified FD (systematically
5566 * the one in epoll_events[0], fd#7) would sometimes
5567 * be set EPOLL_OUT while asked for a read ! This is
5568 * with the 2.4 epoll patch. The workaround is to
5569 * delete then recreate in case of modification.
5570 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5571 * nor RHEL kernels.
5572 */
5573
5574 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5575 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5576
5577 if ((sr | sw))
5578 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5579#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005580 if ((pr | pw)) {
5581 /* the file-descriptor already exists... */
5582 if ((sr | sw)) {
5583 /* ...and it will still exist */
5584 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5585 // perror("epoll_ctl(MOD)");
5586 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005587 }
5588 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005589 /* ...and it will be removed */
5590 if (fdtab[fd].state != FD_STCLOSE &&
5591 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5592 // perror("epoll_ctl(DEL)");
5593 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005594 }
5595 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005596 } else {
5597 /* the file-descriptor did not exist, let's add it */
5598 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5599 // perror("epoll_ctl(ADD)");
5600 // exit(1);
5601 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005602 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005603#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005604 }
5605 ((int*)PrevReadEvent)[fds] = rn;
5606 ((int*)PrevWriteEvent)[fds] = wn;
5607 }
5608 }
5609
5610 /* now let's wait for events */
5611 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5612 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005613
willy tarreau1c2ad212005-12-18 01:11:29 +01005614 for (count = 0; count < status; count++) {
5615 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01005616
5617 if (FD_ISSET(fd, StaticReadEvent)) {
5618 if (fdtab[fd].state == FD_STCLOSE)
5619 continue;
5620 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5621 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005622 }
willy tarreau05be12b2006-03-19 19:35:00 +01005623
5624 if (FD_ISSET(fd, StaticWriteEvent)) {
5625 if (fdtab[fd].state == FD_STCLOSE)
5626 continue;
5627 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5628 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005629 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005630 }
5631 }
5632 return 1;
5633}
5634#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005635
willy tarreauad90a0c2005-12-18 01:09:15 +01005636
willy tarreau5cbea6f2005-12-17 12:48:26 +01005637
willy tarreau1c2ad212005-12-18 01:11:29 +01005638#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005639
willy tarreau1c2ad212005-12-18 01:11:29 +01005640/*
5641 * Main poll() loop.
5642 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005643
willy tarreau1c2ad212005-12-18 01:11:29 +01005644/* does 3 actions :
5645 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5646 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5647 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5648 *
5649 * returns 0 if initialization failed, !0 otherwise.
5650 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005651
willy tarreau1c2ad212005-12-18 01:11:29 +01005652int poll_loop(int action) {
5653 int next_time;
5654 int status;
5655 int fd, nbfd;
5656
5657 int fds, count;
5658 int sr, sw;
5659 unsigned rn, wn; /* read new, write new */
5660
5661 /* private data */
5662 static struct pollfd *poll_events = NULL;
5663
5664 if (action == POLL_LOOP_ACTION_INIT) {
5665 poll_events = (struct pollfd*)
5666 calloc(1, sizeof(struct pollfd) * global.maxsock);
5667 return 1;
5668 }
5669 else if (action == POLL_LOOP_ACTION_CLEAN) {
5670 if (poll_events)
5671 free(poll_events);
5672 return 1;
5673 }
5674
5675 /* OK, it's POLL_LOOP_ACTION_RUN */
5676
5677 tv_now(&now);
5678
5679 while (1) {
5680 next_time = process_runnable_tasks();
5681
5682 /* stop when there's no connection left and we don't allow them anymore */
5683 if (!actconn && listeners == 0)
5684 break;
5685
5686#if STATTIME > 0
5687 {
5688 int time2;
5689 time2 = stats();
5690 next_time = MINTIME(time2, next_time);
5691 }
5692#endif
5693
5694
5695 nbfd = 0;
5696 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5697
5698 rn = ((int*)StaticReadEvent)[fds];
5699 wn = ((int*)StaticWriteEvent)[fds];
5700
5701 if ((rn|wn)) {
5702 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5703#define FDSETS_ARE_INT_ALIGNED
5704#ifdef FDSETS_ARE_INT_ALIGNED
5705
5706#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5707#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5708 sr = (rn >> count) & 1;
5709 sw = (wn >> count) & 1;
5710#else
5711 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5712 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5713#endif
5714#else
5715 sr = FD_ISSET(fd, StaticReadEvent);
5716 sw = FD_ISSET(fd, StaticWriteEvent);
5717#endif
5718 if ((sr|sw)) {
5719 poll_events[nbfd].fd = fd;
5720 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5721 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005722 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005723 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005724 }
5725 }
5726
5727 /* now let's wait for events */
5728 status = poll(poll_events, nbfd, next_time);
5729 tv_now(&now);
5730
5731 for (count = 0; status > 0 && count < nbfd; count++) {
5732 fd = poll_events[count].fd;
5733
5734 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5735 continue;
5736
5737 /* ok, we found one active fd */
5738 status--;
5739
willy tarreau05be12b2006-03-19 19:35:00 +01005740 if (FD_ISSET(fd, StaticReadEvent)) {
5741 if (fdtab[fd].state == FD_STCLOSE)
5742 continue;
5743 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5744 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005745 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005746
willy tarreau05be12b2006-03-19 19:35:00 +01005747 if (FD_ISSET(fd, StaticWriteEvent)) {
5748 if (fdtab[fd].state == FD_STCLOSE)
5749 continue;
5750 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5751 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005752 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005753 }
5754 }
5755 return 1;
5756}
willy tarreauad90a0c2005-12-18 01:09:15 +01005757#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005758
willy tarreauad90a0c2005-12-18 01:09:15 +01005759
willy tarreauad90a0c2005-12-18 01:09:15 +01005760
willy tarreau1c2ad212005-12-18 01:11:29 +01005761/*
5762 * Main select() loop.
5763 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005764
willy tarreau1c2ad212005-12-18 01:11:29 +01005765/* does 3 actions :
5766 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5767 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5768 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5769 *
5770 * returns 0 if initialization failed, !0 otherwise.
5771 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005772
willy tarreauad90a0c2005-12-18 01:09:15 +01005773
willy tarreau1c2ad212005-12-18 01:11:29 +01005774int select_loop(int action) {
5775 int next_time;
5776 int status;
5777 int fd,i;
5778 struct timeval delta;
5779 int readnotnull, writenotnull;
5780 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005781
willy tarreau1c2ad212005-12-18 01:11:29 +01005782 if (action == POLL_LOOP_ACTION_INIT) {
5783 ReadEvent = (fd_set *)
5784 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5785 WriteEvent = (fd_set *)
5786 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5787 return 1;
5788 }
5789 else if (action == POLL_LOOP_ACTION_CLEAN) {
5790 if (WriteEvent) free(WriteEvent);
5791 if (ReadEvent) free(ReadEvent);
5792 return 1;
5793 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005794
willy tarreau1c2ad212005-12-18 01:11:29 +01005795 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005796
willy tarreau1c2ad212005-12-18 01:11:29 +01005797 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005798
willy tarreau1c2ad212005-12-18 01:11:29 +01005799 while (1) {
5800 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005801
willy tarreau1c2ad212005-12-18 01:11:29 +01005802 /* stop when there's no connection left and we don't allow them anymore */
5803 if (!actconn && listeners == 0)
5804 break;
5805
5806#if STATTIME > 0
5807 {
5808 int time2;
5809 time2 = stats();
5810 next_time = MINTIME(time2, next_time);
5811 }
5812#endif
5813
willy tarreau1c2ad212005-12-18 01:11:29 +01005814 if (next_time > 0) { /* FIXME */
5815 /* Convert to timeval */
5816 /* to avoid eventual select loops due to timer precision */
5817 next_time += SCHEDULER_RESOLUTION;
5818 delta.tv_sec = next_time / 1000;
5819 delta.tv_usec = (next_time % 1000) * 1000;
5820 }
5821 else if (next_time == 0) { /* allow select to return immediately when needed */
5822 delta.tv_sec = delta.tv_usec = 0;
5823 }
5824
5825
5826 /* let's restore fdset state */
5827
5828 readnotnull = 0; writenotnull = 0;
5829 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5830 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5831 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5832 }
5833
5834 // /* just a verification code, needs to be removed for performance */
5835 // for (i=0; i<maxfd; i++) {
5836 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5837 // abort();
5838 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5839 // abort();
5840 //
5841 // }
5842
5843 status = select(maxfd,
5844 readnotnull ? ReadEvent : NULL,
5845 writenotnull ? WriteEvent : NULL,
5846 NULL,
5847 (next_time >= 0) ? &delta : NULL);
5848
5849 /* this is an experiment on the separation of the select work */
5850 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5851 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5852
5853 tv_now(&now);
5854
5855 if (status > 0) { /* must proceed with events */
5856
5857 int fds;
5858 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005859
willy tarreau1c2ad212005-12-18 01:11:29 +01005860 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5861 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5862 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5863
5864 /* if we specify read first, the accepts and zero reads will be
5865 * seen first. Moreover, system buffers will be flushed faster.
5866 */
willy tarreau05be12b2006-03-19 19:35:00 +01005867 if (FD_ISSET(fd, ReadEvent)) {
5868 if (fdtab[fd].state == FD_STCLOSE)
5869 continue;
5870 fdtab[fd].read(fd);
5871 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005872
willy tarreau05be12b2006-03-19 19:35:00 +01005873 if (FD_ISSET(fd, WriteEvent)) {
5874 if (fdtab[fd].state == FD_STCLOSE)
5875 continue;
5876 fdtab[fd].write(fd);
5877 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005878 }
5879 }
5880 else {
5881 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005882 }
willy tarreau0f7af912005-12-17 12:21:26 +01005883 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005884 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005885}
5886
5887
5888#if STATTIME > 0
5889/*
5890 * Display proxy statistics regularly. It is designed to be called from the
5891 * select_loop().
5892 */
5893int stats(void) {
5894 static int lines;
5895 static struct timeval nextevt;
5896 static struct timeval lastevt;
5897 static struct timeval starttime = {0,0};
5898 unsigned long totaltime, deltatime;
5899 int ret;
5900
willy tarreau750a4722005-12-17 13:21:24 +01005901 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005902 deltatime = (tv_diff(&lastevt, &now)?:1);
5903 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005904
willy tarreau9fe663a2005-12-17 13:02:59 +01005905 if (global.mode & MODE_STATS) {
5906 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005907 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005908 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5909 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005910 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005911 actconn, totalconn,
5912 stats_tsk_new, stats_tsk_good,
5913 stats_tsk_left, stats_tsk_right,
5914 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5915 }
5916 }
5917
5918 tv_delayfrom(&nextevt, &now, STATTIME);
5919
5920 lastevt=now;
5921 }
5922 ret = tv_remain(&now, &nextevt);
5923 return ret;
5924}
5925#endif
5926
5927
5928/*
5929 * this function enables proxies when there are enough free sessions,
5930 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005931 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005932 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005933 */
5934static int maintain_proxies(void) {
5935 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005936 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005937 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005938
5939 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005940 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005941
5942 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005943 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005944 while (p) {
5945 if (p->nbconn < p->maxconn) {
5946 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005947 for (l = p->listen; l != NULL; l = l->next) {
5948 FD_SET(l->fd, StaticReadEvent);
5949 }
willy tarreau0f7af912005-12-17 12:21:26 +01005950 p->state = PR_STRUN;
5951 }
5952 }
5953 else {
5954 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005955 for (l = p->listen; l != NULL; l = l->next) {
5956 FD_CLR(l->fd, StaticReadEvent);
5957 }
willy tarreau0f7af912005-12-17 12:21:26 +01005958 p->state = PR_STIDLE;
5959 }
5960 }
5961 p = p->next;
5962 }
5963 }
5964 else { /* block all proxies */
5965 while (p) {
5966 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005967 for (l = p->listen; l != NULL; l = l->next) {
5968 FD_CLR(l->fd, StaticReadEvent);
5969 }
willy tarreau0f7af912005-12-17 12:21:26 +01005970 p->state = PR_STIDLE;
5971 }
5972 p = p->next;
5973 }
5974 }
5975
willy tarreau5cbea6f2005-12-17 12:48:26 +01005976 if (stopping) {
5977 p = proxy;
5978 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01005979 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005980 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01005981 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005982 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005983 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005984 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005985
willy tarreaua41a8b42005-12-17 14:02:24 +01005986 for (l = p->listen; l != NULL; l = l->next) {
5987 fd_delete(l->fd);
5988 listeners--;
5989 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01005990 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005991 }
5992 else {
5993 tleft = MINTIME(t, tleft);
5994 }
5995 }
5996 p = p->next;
5997 }
5998 }
5999 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006000}
6001
6002/*
6003 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006004 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6005 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006006 */
6007static void soft_stop(void) {
6008 struct proxy *p;
6009
6010 stopping = 1;
6011 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006012 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006013 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006014 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006015 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006016 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006017 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006018 }
willy tarreau0f7af912005-12-17 12:21:26 +01006019 p = p->next;
6020 }
6021}
6022
willy tarreaudbd3bef2006-01-20 19:35:18 +01006023static void pause_proxy(struct proxy *p) {
6024 struct listener *l;
6025 for (l = p->listen; l != NULL; l = l->next) {
6026 shutdown(l->fd, SHUT_RD);
6027 FD_CLR(l->fd, StaticReadEvent);
6028 p->state = PR_STPAUSED;
6029 }
6030}
6031
6032/*
6033 * This function temporarily disables listening so that another new instance
6034 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006035 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006036 * the proxy, or a SIGTTIN can be sent to listen again.
6037 */
6038static void pause_proxies(void) {
6039 struct proxy *p;
6040
6041 p = proxy;
6042 tv_now(&now); /* else, the old time before select will be used */
6043 while (p) {
6044 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6045 Warning("Pausing proxy %s.\n", p->id);
6046 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6047 pause_proxy(p);
6048 }
6049 p = p->next;
6050 }
6051}
6052
6053
6054/*
6055 * This function reactivates listening. This can be used after a call to
6056 * sig_pause(), for example when a new instance has failed starting up.
6057 * It is designed to be called upon reception of a SIGTTIN.
6058 */
6059static void listen_proxies(void) {
6060 struct proxy *p;
6061 struct listener *l;
6062
6063 p = proxy;
6064 tv_now(&now); /* else, the old time before select will be used */
6065 while (p) {
6066 if (p->state == PR_STPAUSED) {
6067 Warning("Enabling proxy %s.\n", p->id);
6068 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6069
6070 for (l = p->listen; l != NULL; l = l->next) {
6071 if (listen(l->fd, p->maxconn) == 0) {
6072 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6073 FD_SET(l->fd, StaticReadEvent);
6074 p->state = PR_STRUN;
6075 }
6076 else
6077 p->state = PR_STIDLE;
6078 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006079 int port;
6080
6081 if (l->addr.ss_family == AF_INET6)
6082 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6083 else
6084 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6085
willy tarreaudbd3bef2006-01-20 19:35:18 +01006086 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006087 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006088 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006089 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006090 /* Another port might have been enabled. Let's stop everything. */
6091 pause_proxy(p);
6092 break;
6093 }
6094 }
6095 }
6096 p = p->next;
6097 }
6098}
6099
6100
willy tarreau0f7af912005-12-17 12:21:26 +01006101/*
6102 * upon SIGUSR1, let's have a soft stop.
6103 */
6104void sig_soft_stop(int sig) {
6105 soft_stop();
6106 signal(sig, SIG_IGN);
6107}
6108
willy tarreaudbd3bef2006-01-20 19:35:18 +01006109/*
6110 * upon SIGTTOU, we pause everything
6111 */
6112void sig_pause(int sig) {
6113 pause_proxies();
6114 signal(sig, sig_pause);
6115}
willy tarreau0f7af912005-12-17 12:21:26 +01006116
willy tarreau8337c6b2005-12-17 13:41:01 +01006117/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006118 * upon SIGTTIN, let's have a soft stop.
6119 */
6120void sig_listen(int sig) {
6121 listen_proxies();
6122 signal(sig, sig_listen);
6123}
6124
6125/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006126 * this function dumps every server's state when the process receives SIGHUP.
6127 */
6128void sig_dump_state(int sig) {
6129 struct proxy *p = proxy;
6130
6131 Warning("SIGHUP received, dumping servers states.\n");
6132 while (p) {
6133 struct server *s = p->srv;
6134
6135 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
6136 while (s) {
6137 if (s->state & SRV_RUNNING) {
willy tarreaufd6dfe72006-03-19 19:38:19 +01006138 Warning("SIGHUP: Server %s/%s is UP.\n", p->id, s->id);
6139 send_log(p, LOG_NOTICE, "SIGUP: Server %s/%s is UP.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006140 }
6141 else {
willy tarreaufd6dfe72006-03-19 19:38:19 +01006142 Warning("SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
6143 send_log(p, LOG_NOTICE, "SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006144 }
6145 s = s->next;
6146 }
willy tarreaudd07e972005-12-18 00:48:48 +01006147
willy tarreau62084d42006-03-24 18:57:41 +01006148 if (p->srv_act == 0) {
6149 if (p->srv_bck) {
6150 Warning("SIGHUP: Proxy %s is running on backup servers !\n", p->id);
6151 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s is running on backup servers !\n", p->id);
6152 } else {
6153 Warning("SIGHUP: Proxy %s has no server available !\n", p->id);
6154 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s has no server available !\n", p->id);
6155 }
6156 }
willy tarreaudd07e972005-12-18 00:48:48 +01006157
willy tarreau8337c6b2005-12-17 13:41:01 +01006158 p = p->next;
6159 }
6160 signal(sig, sig_dump_state);
6161}
6162
willy tarreau0f7af912005-12-17 12:21:26 +01006163void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006164 struct task *t, *tnext;
6165 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006166
willy tarreau5cbea6f2005-12-17 12:48:26 +01006167 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
6168 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
6169 tnext = t->next;
6170 s = t->context;
6171 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6172 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6173 "req=%d, rep=%d, clifd=%d\n",
6174 s, tv_remain(&now, &t->expire),
6175 s->cli_state,
6176 s->srv_state,
6177 FD_ISSET(s->cli_fd, StaticReadEvent),
6178 FD_ISSET(s->cli_fd, StaticWriteEvent),
6179 FD_ISSET(s->srv_fd, StaticReadEvent),
6180 FD_ISSET(s->srv_fd, StaticWriteEvent),
6181 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6182 );
willy tarreau0f7af912005-12-17 12:21:26 +01006183 }
willy tarreau12350152005-12-18 01:03:27 +01006184}
6185
willy tarreau64a3cc32005-12-18 01:13:11 +01006186#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006187static void fast_stop(void)
6188{
6189 struct proxy *p;
6190 p = proxy;
6191 while (p) {
6192 p->grace = 0;
6193 p = p->next;
6194 }
6195 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006196}
6197
willy tarreau12350152005-12-18 01:03:27 +01006198void sig_int(int sig) {
6199 /* This would normally be a hard stop,
6200 but we want to be sure about deallocation,
6201 and so on, so we do a soft stop with
6202 0 GRACE time
6203 */
6204 fast_stop();
6205 /* If we are killed twice, we decide to die*/
6206 signal(sig, SIG_DFL);
6207}
6208
6209void sig_term(int sig) {
6210 /* This would normally be a hard stop,
6211 but we want to be sure about deallocation,
6212 and so on, so we do a soft stop with
6213 0 GRACE time
6214 */
6215 fast_stop();
6216 /* If we are killed twice, we decide to die*/
6217 signal(sig, SIG_DFL);
6218}
willy tarreau64a3cc32005-12-18 01:13:11 +01006219#endif
willy tarreau12350152005-12-18 01:03:27 +01006220
willy tarreauc1f47532005-12-18 01:08:26 +01006221/* returns the pointer to an error in the replacement string, or NULL if OK */
6222char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006223 struct hdr_exp *exp;
6224
willy tarreauc1f47532005-12-18 01:08:26 +01006225 if (replace != NULL) {
6226 char *err;
6227 err = check_replace_string(replace);
6228 if (err)
6229 return err;
6230 }
6231
willy tarreaue39cd132005-12-17 13:00:18 +01006232 while (*head != NULL)
6233 head = &(*head)->next;
6234
6235 exp = calloc(1, sizeof(struct hdr_exp));
6236
6237 exp->preg = preg;
6238 exp->replace = replace;
6239 exp->action = action;
6240 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006241
6242 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006243}
6244
willy tarreau9fe663a2005-12-17 13:02:59 +01006245
willy tarreau0f7af912005-12-17 12:21:26 +01006246/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006247 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006248 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006249int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006250
willy tarreau9fe663a2005-12-17 13:02:59 +01006251 if (!strcmp(args[0], "global")) { /* new section */
6252 /* no option, nothing special to do */
6253 return 0;
6254 }
6255 else if (!strcmp(args[0], "daemon")) {
6256 global.mode |= MODE_DAEMON;
6257 }
6258 else if (!strcmp(args[0], "debug")) {
6259 global.mode |= MODE_DEBUG;
6260 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006261 else if (!strcmp(args[0], "noepoll")) {
6262 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6263 }
6264 else if (!strcmp(args[0], "nopoll")) {
6265 cfg_polling_mechanism &= ~POLL_USE_POLL;
6266 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006267 else if (!strcmp(args[0], "quiet")) {
6268 global.mode |= MODE_QUIET;
6269 }
6270 else if (!strcmp(args[0], "stats")) {
6271 global.mode |= MODE_STATS;
6272 }
6273 else if (!strcmp(args[0], "uid")) {
6274 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006275 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006276 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006277 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006278 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006279 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006280 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006281 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006282 global.uid = atol(args[1]);
6283 }
6284 else if (!strcmp(args[0], "gid")) {
6285 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006286 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006287 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006288 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006289 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006290 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006291 return -1;
6292 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006293 global.gid = atol(args[1]);
6294 }
6295 else if (!strcmp(args[0], "nbproc")) {
6296 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006297 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006298 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006299 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006300 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006301 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006302 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006303 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006304 global.nbproc = atol(args[1]);
6305 }
6306 else if (!strcmp(args[0], "maxconn")) {
6307 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006308 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006309 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006310 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006311 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006312 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006313 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006314 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006315 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006316#ifdef SYSTEM_MAXCONN
6317 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6318 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);
6319 global.maxconn = DEFAULT_MAXCONN;
6320 }
6321#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006322 }
willy tarreaub1285d52005-12-18 01:20:14 +01006323 else if (!strcmp(args[0], "ulimit-n")) {
6324 if (global.rlimit_nofile != 0) {
6325 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6326 return 0;
6327 }
6328 if (*(args[1]) == 0) {
6329 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6330 return -1;
6331 }
6332 global.rlimit_nofile = atol(args[1]);
6333 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006334 else if (!strcmp(args[0], "chroot")) {
6335 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006336 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006337 return 0;
6338 }
6339 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006340 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006341 return -1;
6342 }
6343 global.chroot = strdup(args[1]);
6344 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006345 else if (!strcmp(args[0], "pidfile")) {
6346 if (global.pidfile != NULL) {
6347 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6348 return 0;
6349 }
6350 if (*(args[1]) == 0) {
6351 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6352 return -1;
6353 }
6354 global.pidfile = strdup(args[1]);
6355 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006356 else if (!strcmp(args[0], "log")) { /* syslog server address */
6357 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006358 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006359
6360 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006361 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006362 return -1;
6363 }
6364
6365 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6366 if (!strcmp(log_facilities[facility], args[2]))
6367 break;
6368
6369 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006370 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006371 exit(1);
6372 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006373
6374 level = 7; /* max syslog level = debug */
6375 if (*(args[3])) {
6376 while (level >= 0 && strcmp(log_levels[level], args[3]))
6377 level--;
6378 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006379 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006380 exit(1);
6381 }
6382 }
6383
willy tarreau9fe663a2005-12-17 13:02:59 +01006384 sa = str2sa(args[1]);
6385 if (!sa->sin_port)
6386 sa->sin_port = htons(SYSLOG_PORT);
6387
6388 if (global.logfac1 == -1) {
6389 global.logsrv1 = *sa;
6390 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006391 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006392 }
6393 else if (global.logfac2 == -1) {
6394 global.logsrv2 = *sa;
6395 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006396 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006397 }
6398 else {
6399 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6400 return -1;
6401 }
6402
6403 }
6404 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006405 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006406 return -1;
6407 }
6408 return 0;
6409}
6410
6411
willy tarreaua41a8b42005-12-17 14:02:24 +01006412void init_default_instance() {
6413 memset(&defproxy, 0, sizeof(defproxy));
6414 defproxy.mode = PR_MODE_TCP;
6415 defproxy.state = PR_STNEW;
6416 defproxy.maxconn = cfg_maxpconn;
6417 defproxy.conn_retries = CONN_RETRIES;
6418 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6419}
6420
willy tarreau9fe663a2005-12-17 13:02:59 +01006421/*
6422 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6423 */
6424int cfg_parse_listen(char *file, int linenum, char **args) {
6425 static struct proxy *curproxy = NULL;
6426 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006427 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006428 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006429
6430 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006431 if (!*args[1]) {
6432 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6433 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006434 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006435 return -1;
6436 }
6437
6438 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006439 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006440 return -1;
6441 }
6442 curproxy->next = proxy;
6443 proxy = curproxy;
6444 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006445
6446 /* parse the listener address if any */
6447 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006448 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006449 if (!curproxy->listen)
6450 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006451 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01006452 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006453
willy tarreau9fe663a2005-12-17 13:02:59 +01006454 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006455 curproxy->state = defproxy.state;
6456 curproxy->maxconn = defproxy.maxconn;
6457 curproxy->conn_retries = defproxy.conn_retries;
6458 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006459
6460 if (defproxy.check_req)
6461 curproxy->check_req = strdup(defproxy.check_req);
6462 curproxy->check_len = defproxy.check_len;
6463
6464 if (defproxy.cookie_name)
6465 curproxy->cookie_name = strdup(defproxy.cookie_name);
6466 curproxy->cookie_len = defproxy.cookie_len;
6467
6468 if (defproxy.capture_name)
6469 curproxy->capture_name = strdup(defproxy.capture_name);
6470 curproxy->capture_namelen = defproxy.capture_namelen;
6471 curproxy->capture_len = defproxy.capture_len;
6472
6473 if (defproxy.errmsg.msg400)
6474 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6475 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6476
6477 if (defproxy.errmsg.msg403)
6478 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6479 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6480
6481 if (defproxy.errmsg.msg408)
6482 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6483 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6484
6485 if (defproxy.errmsg.msg500)
6486 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6487 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6488
6489 if (defproxy.errmsg.msg502)
6490 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6491 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6492
6493 if (defproxy.errmsg.msg503)
6494 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6495 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6496
6497 if (defproxy.errmsg.msg504)
6498 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6499 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6500
willy tarreaua41a8b42005-12-17 14:02:24 +01006501 curproxy->clitimeout = defproxy.clitimeout;
6502 curproxy->contimeout = defproxy.contimeout;
6503 curproxy->srvtimeout = defproxy.srvtimeout;
6504 curproxy->mode = defproxy.mode;
6505 curproxy->logfac1 = defproxy.logfac1;
6506 curproxy->logsrv1 = defproxy.logsrv1;
6507 curproxy->loglev1 = defproxy.loglev1;
6508 curproxy->logfac2 = defproxy.logfac2;
6509 curproxy->logsrv2 = defproxy.logsrv2;
6510 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006511 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006512 curproxy->grace = defproxy.grace;
6513 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006514 curproxy->mon_net = defproxy.mon_net;
6515 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006516 return 0;
6517 }
6518 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006519 /* some variables may have already been initialized earlier */
6520 if (defproxy.check_req) free(defproxy.check_req);
6521 if (defproxy.cookie_name) free(defproxy.cookie_name);
6522 if (defproxy.capture_name) free(defproxy.capture_name);
6523 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6524 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6525 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6526 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6527 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6528 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6529 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6530
6531 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006532 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006533 return 0;
6534 }
6535 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006536 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006537 return -1;
6538 }
6539
willy tarreaua41a8b42005-12-17 14:02:24 +01006540 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6541 if (curproxy == &defproxy) {
6542 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6543 return -1;
6544 }
6545
6546 if (strchr(args[1], ':') == NULL) {
6547 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6548 file, linenum, args[0]);
6549 return -1;
6550 }
6551 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006552 if (!curproxy->listen)
6553 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006554 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006555 return 0;
6556 }
willy tarreaub1285d52005-12-18 01:20:14 +01006557 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6558 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6559 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6560 file, linenum, args[0]);
6561 return -1;
6562 }
6563 /* flush useless bits */
6564 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6565 return 0;
6566 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006567 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006568 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6569 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6570 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6571 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006572 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006573 return -1;
6574 }
6575 }
6576 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006577 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006578 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006579 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6580 curproxy->state = PR_STNEW;
6581 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006582 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6583 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006584// if (curproxy == &defproxy) {
6585// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6586// return -1;
6587// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006588
willy tarreau9fe663a2005-12-17 13:02:59 +01006589 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006590// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6591// file, linenum);
6592// return 0;
6593 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006594 }
6595
6596 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006597 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6598 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006599 return -1;
6600 }
6601 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006602 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006603
6604 cur_arg = 2;
6605 while (*(args[cur_arg])) {
6606 if (!strcmp(args[cur_arg], "rewrite")) {
6607 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006608 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006609 else if (!strcmp(args[cur_arg], "indirect")) {
6610 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006611 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006612 else if (!strcmp(args[cur_arg], "insert")) {
6613 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006614 }
willy tarreau240afa62005-12-17 13:14:35 +01006615 else if (!strcmp(args[cur_arg], "nocache")) {
6616 curproxy->options |= PR_O_COOK_NOC;
6617 }
willy tarreaucd878942005-12-17 13:27:43 +01006618 else if (!strcmp(args[cur_arg], "postonly")) {
6619 curproxy->options |= PR_O_COOK_POST;
6620 }
willy tarreau0174f312005-12-18 01:02:42 +01006621 else if (!strcmp(args[cur_arg], "prefix")) {
6622 curproxy->options |= PR_O_COOK_PFX;
6623 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006624 else {
willy tarreau0174f312005-12-18 01:02:42 +01006625 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006626 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006627 return -1;
6628 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006629 cur_arg++;
6630 }
willy tarreau0174f312005-12-18 01:02:42 +01006631 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6632 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6633 file, linenum);
6634 return -1;
6635 }
6636
6637 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6638 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006639 file, linenum);
6640 return -1;
6641 }
willy tarreau12350152005-12-18 01:03:27 +01006642 }/* end else if (!strcmp(args[0], "cookie")) */
6643 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6644// if (curproxy == &defproxy) {
6645// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6646// return -1;
6647// }
6648
6649 if (curproxy->appsession_name != NULL) {
6650// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6651// file, linenum);
6652// return 0;
6653 free(curproxy->appsession_name);
6654 }
6655
6656 if (*(args[5]) == 0) {
6657 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6658 file, linenum, args[0]);
6659 return -1;
6660 }
6661 have_appsession = 1;
6662 curproxy->appsession_name = strdup(args[1]);
6663 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6664 curproxy->appsession_len = atoi(args[3]);
6665 curproxy->appsession_timeout = atoi(args[5]);
6666 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6667 if (rc) {
6668 Alert("Error Init Appsession Hashtable.\n");
6669 return -1;
6670 }
6671 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006672 else if (!strcmp(args[0], "capture")) {
6673 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6674 // if (curproxy == &defproxy) {
6675 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6676 // return -1;
6677 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006678
willy tarreau4302f492005-12-18 01:00:37 +01006679 if (curproxy->capture_name != NULL) {
6680 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6681 // file, linenum, args[0]);
6682 // return 0;
6683 free(curproxy->capture_name);
6684 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006685
willy tarreau4302f492005-12-18 01:00:37 +01006686 if (*(args[4]) == 0) {
6687 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6688 file, linenum, args[0]);
6689 return -1;
6690 }
6691 curproxy->capture_name = strdup(args[2]);
6692 curproxy->capture_namelen = strlen(curproxy->capture_name);
6693 curproxy->capture_len = atol(args[4]);
6694 if (curproxy->capture_len >= CAPTURE_LEN) {
6695 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6696 file, linenum, CAPTURE_LEN - 1);
6697 curproxy->capture_len = CAPTURE_LEN - 1;
6698 }
6699 curproxy->to_log |= LW_COOKIE;
6700 }
6701 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6702 struct cap_hdr *hdr;
6703
6704 if (curproxy == &defproxy) {
6705 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6706 return -1;
6707 }
6708
6709 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6710 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6711 file, linenum, args[0], args[1]);
6712 return -1;
6713 }
6714
6715 hdr = calloc(sizeof(struct cap_hdr), 1);
6716 hdr->next = curproxy->req_cap;
6717 hdr->name = strdup(args[3]);
6718 hdr->namelen = strlen(args[3]);
6719 hdr->len = atol(args[5]);
6720 hdr->index = curproxy->nb_req_cap++;
6721 curproxy->req_cap = hdr;
6722 curproxy->to_log |= LW_REQHDR;
6723 }
6724 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6725 struct cap_hdr *hdr;
6726
6727 if (curproxy == &defproxy) {
6728 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6729 return -1;
6730 }
6731
6732 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6733 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6734 file, linenum, args[0], args[1]);
6735 return -1;
6736 }
6737 hdr = calloc(sizeof(struct cap_hdr), 1);
6738 hdr->next = curproxy->rsp_cap;
6739 hdr->name = strdup(args[3]);
6740 hdr->namelen = strlen(args[3]);
6741 hdr->len = atol(args[5]);
6742 hdr->index = curproxy->nb_rsp_cap++;
6743 curproxy->rsp_cap = hdr;
6744 curproxy->to_log |= LW_RSPHDR;
6745 }
6746 else {
6747 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006748 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006749 return -1;
6750 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006751 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006752 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006753 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006754 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006755 return 0;
6756 }
6757 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006758 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6759 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006760 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006761 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006762 curproxy->contimeout = atol(args[1]);
6763 }
6764 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006765 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006766 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6767 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006768 return 0;
6769 }
6770 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006771 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6772 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006773 return -1;
6774 }
6775 curproxy->clitimeout = atol(args[1]);
6776 }
6777 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006778 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006779 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006780 return 0;
6781 }
6782 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006783 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6784 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006785 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006786 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006787 curproxy->srvtimeout = atol(args[1]);
6788 }
6789 else if (!strcmp(args[0], "retries")) { /* connection retries */
6790 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006791 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6792 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006793 return -1;
6794 }
6795 curproxy->conn_retries = atol(args[1]);
6796 }
6797 else if (!strcmp(args[0], "option")) {
6798 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006799 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006800 return -1;
6801 }
6802 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006803 /* enable reconnections to dispatch */
6804 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006805#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006806 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006807 /* enable transparent proxy connections */
6808 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006809#endif
6810 else if (!strcmp(args[1], "keepalive"))
6811 /* enable keep-alive */
6812 curproxy->options |= PR_O_KEEPALIVE;
6813 else if (!strcmp(args[1], "forwardfor"))
6814 /* insert x-forwarded-for field */
6815 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006816 else if (!strcmp(args[1], "logasap"))
6817 /* log as soon as possible, without waiting for the session to complete */
6818 curproxy->options |= PR_O_LOGASAP;
6819 else if (!strcmp(args[1], "httpclose"))
6820 /* force connection: close in both directions in HTTP mode */
6821 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01006822 else if (!strcmp(args[1], "forceclose"))
6823 /* force connection: close in both directions in HTTP mode and enforce end of session */
6824 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006825 else if (!strcmp(args[1], "checkcache"))
6826 /* require examination of cacheability of the 'set-cookie' field */
6827 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006828 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006829 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006830 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006831 else if (!strcmp(args[1], "tcplog"))
6832 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006833 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006834 else if (!strcmp(args[1], "dontlognull")) {
6835 /* don't log empty requests */
6836 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006837 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006838 else if (!strcmp(args[1], "tcpka")) {
6839 /* enable TCP keep-alives on client and server sessions */
6840 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6841 }
6842 else if (!strcmp(args[1], "clitcpka")) {
6843 /* enable TCP keep-alives on client sessions */
6844 curproxy->options |= PR_O_TCP_CLI_KA;
6845 }
6846 else if (!strcmp(args[1], "srvtcpka")) {
6847 /* enable TCP keep-alives on server sessions */
6848 curproxy->options |= PR_O_TCP_SRV_KA;
6849 }
Willy TARREAU3481c462006-03-01 22:37:57 +01006850 else if (!strcmp(args[1], "allbackups")) {
6851 /* Use all backup servers simultaneously */
6852 curproxy->options |= PR_O_USE_ALL_BK;
6853 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006854 else if (!strcmp(args[1], "httpchk")) {
6855 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006856 if (curproxy->check_req != NULL) {
6857 free(curproxy->check_req);
6858 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006859 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006860 if (!*args[2]) { /* no argument */
6861 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6862 curproxy->check_len = strlen(DEF_CHECK_REQ);
6863 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006864 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6865 curproxy->check_req = (char *)malloc(reqlen);
6866 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6867 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006868 } else { /* more arguments : METHOD URI [HTTP_VER] */
6869 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6870 if (*args[4])
6871 reqlen += strlen(args[4]);
6872 else
6873 reqlen += strlen("HTTP/1.0");
6874
6875 curproxy->check_req = (char *)malloc(reqlen);
6876 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6877 "%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 +01006878 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006879 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006880 else if (!strcmp(args[1], "persist")) {
6881 /* persist on using the server specified by the cookie, even when it's down */
6882 curproxy->options |= PR_O_PERSIST;
6883 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006884 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006885 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006886 return -1;
6887 }
6888 return 0;
6889 }
6890 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6891 /* enable reconnections to dispatch */
6892 curproxy->options |= PR_O_REDISP;
6893 }
willy tarreaua1598082005-12-17 13:08:06 +01006894#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006895 else if (!strcmp(args[0], "transparent")) {
6896 /* enable transparent proxy connections */
6897 curproxy->options |= PR_O_TRANSP;
6898 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006899#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006900 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6901 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006902 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006903 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006904 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006905 curproxy->maxconn = atol(args[1]);
6906 }
6907 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6908 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006909 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006910 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006911 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006912 curproxy->grace = atol(args[1]);
6913 }
6914 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006915 if (curproxy == &defproxy) {
6916 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6917 return -1;
6918 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006919 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006920 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006921 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006922 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006923 curproxy->dispatch_addr = *str2sa(args[1]);
6924 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006925 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006926 if (*(args[1])) {
6927 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006928 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006929 }
willy tarreau1a3442d2006-03-24 21:03:20 +01006930 else if (!strcmp(args[1], "source")) {
6931 curproxy->options |= PR_O_BALANCE_SH;
6932 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006933 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01006934 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006935 return -1;
6936 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006937 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006938 else /* if no option is set, use round-robin by default */
6939 curproxy->options |= PR_O_BALANCE_RR;
6940 }
6941 else if (!strcmp(args[0], "server")) { /* server address */
6942 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006943 char *rport;
6944 char *raddr;
6945 short realport;
6946 int do_check;
6947
6948 if (curproxy == &defproxy) {
6949 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6950 return -1;
6951 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006952
willy tarreaua41a8b42005-12-17 14:02:24 +01006953 if (!*args[2]) {
6954 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006955 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006956 return -1;
6957 }
6958 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6959 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6960 return -1;
6961 }
willy tarreau0174f312005-12-18 01:02:42 +01006962
6963 if (curproxy->srv == NULL)
6964 curproxy->srv = newsrv;
6965 else
6966 curproxy->cursrv->next = newsrv;
6967 curproxy->cursrv = newsrv;
6968
6969 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006970 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006971
6972 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006973 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006974 newsrv->id = strdup(args[1]);
6975
6976 /* several ways to check the port component :
6977 * - IP => port=+0, relative
6978 * - IP: => port=+0, relative
6979 * - IP:N => port=N, absolute
6980 * - IP:+N => port=+N, relative
6981 * - IP:-N => port=-N, relative
6982 */
6983 raddr = strdup(args[2]);
6984 rport = strchr(raddr, ':');
6985 if (rport) {
6986 *rport++ = 0;
6987 realport = atol(rport);
6988 if (!isdigit((int)*rport))
6989 newsrv->state |= SRV_MAPPORTS;
6990 } else {
6991 realport = 0;
6992 newsrv->state |= SRV_MAPPORTS;
6993 }
6994
6995 newsrv->addr = *str2sa(raddr);
6996 newsrv->addr.sin_port = htons(realport);
6997 free(raddr);
6998
willy tarreau9fe663a2005-12-17 13:02:59 +01006999 newsrv->curfd = -1; /* no health-check in progress */
7000 newsrv->inter = DEF_CHKINTR;
7001 newsrv->rise = DEF_RISETIME;
7002 newsrv->fall = DEF_FALLTIME;
7003 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7004 cur_arg = 3;
7005 while (*args[cur_arg]) {
7006 if (!strcmp(args[cur_arg], "cookie")) {
7007 newsrv->cookie = strdup(args[cur_arg + 1]);
7008 newsrv->cklen = strlen(args[cur_arg + 1]);
7009 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007010 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007011 else if (!strcmp(args[cur_arg], "rise")) {
7012 newsrv->rise = atol(args[cur_arg + 1]);
7013 newsrv->health = newsrv->rise;
7014 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007015 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007016 else if (!strcmp(args[cur_arg], "fall")) {
7017 newsrv->fall = atol(args[cur_arg + 1]);
7018 cur_arg += 2;
7019 }
7020 else if (!strcmp(args[cur_arg], "inter")) {
7021 newsrv->inter = atol(args[cur_arg + 1]);
7022 cur_arg += 2;
7023 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007024 else if (!strcmp(args[cur_arg], "port")) {
7025 newsrv->check_port = atol(args[cur_arg + 1]);
7026 cur_arg += 2;
7027 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007028 else if (!strcmp(args[cur_arg], "backup")) {
7029 newsrv->state |= SRV_BACKUP;
7030 cur_arg ++;
7031 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007032 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007033 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007034 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007035 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007036 }
willy tarreau0174f312005-12-18 01:02:42 +01007037 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7038 if (!*args[cur_arg + 1]) {
7039 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7040 file, linenum, "source");
7041 return -1;
7042 }
7043 newsrv->state |= SRV_BIND_SRC;
7044 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7045 cur_arg += 2;
7046 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007047 else {
willy tarreau0174f312005-12-18 01:02:42 +01007048 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 +01007049 file, linenum, newsrv->id);
7050 return -1;
7051 }
7052 }
7053
7054 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007055 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7056 newsrv->check_port = realport; /* by default */
7057 if (!newsrv->check_port) {
7058 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 +01007059 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007060 return -1;
7061 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007062 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007063 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007064
willy tarreau62084d42006-03-24 18:57:41 +01007065 if (newsrv->state & SRV_BACKUP)
7066 curproxy->srv_bck++;
7067 else
7068 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007069 }
7070 else if (!strcmp(args[0], "log")) { /* syslog server address */
7071 struct sockaddr_in *sa;
7072 int facility;
7073
7074 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7075 curproxy->logfac1 = global.logfac1;
7076 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007077 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007078 curproxy->logfac2 = global.logfac2;
7079 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007080 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007081 }
7082 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007083 int level;
7084
willy tarreau0f7af912005-12-17 12:21:26 +01007085 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7086 if (!strcmp(log_facilities[facility], args[2]))
7087 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007088
willy tarreau0f7af912005-12-17 12:21:26 +01007089 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007090 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007091 exit(1);
7092 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007093
willy tarreau8337c6b2005-12-17 13:41:01 +01007094 level = 7; /* max syslog level = debug */
7095 if (*(args[3])) {
7096 while (level >= 0 && strcmp(log_levels[level], args[3]))
7097 level--;
7098 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007099 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007100 exit(1);
7101 }
7102 }
7103
willy tarreau0f7af912005-12-17 12:21:26 +01007104 sa = str2sa(args[1]);
7105 if (!sa->sin_port)
7106 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007107
willy tarreau0f7af912005-12-17 12:21:26 +01007108 if (curproxy->logfac1 == -1) {
7109 curproxy->logsrv1 = *sa;
7110 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007111 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007112 }
7113 else if (curproxy->logfac2 == -1) {
7114 curproxy->logsrv2 = *sa;
7115 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007116 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007117 }
7118 else {
7119 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007120 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007121 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007122 }
7123 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007124 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007125 file, linenum);
7126 return -1;
7127 }
7128 }
willy tarreaua1598082005-12-17 13:08:06 +01007129 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007130 if (!*args[1]) {
7131 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007132 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007133 return -1;
7134 }
7135
7136 curproxy->source_addr = *str2sa(args[1]);
7137 curproxy->options |= PR_O_BIND_SRC;
7138 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007139 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7140 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007141 if (curproxy == &defproxy) {
7142 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7143 return -1;
7144 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007145
7146 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007147 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7148 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007149 return -1;
7150 }
7151
7152 preg = calloc(1, sizeof(regex_t));
7153 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007154 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007155 return -1;
7156 }
7157
willy tarreauc1f47532005-12-18 01:08:26 +01007158 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7159 if (err) {
7160 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7161 file, linenum, *err);
7162 return -1;
7163 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007164 }
7165 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7166 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007167 if (curproxy == &defproxy) {
7168 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7169 return -1;
7170 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007171
7172 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007173 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007174 return -1;
7175 }
7176
7177 preg = calloc(1, sizeof(regex_t));
7178 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007179 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007180 return -1;
7181 }
7182
7183 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7184 }
7185 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this 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) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007193 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007194 return -1;
7195 }
7196
7197 preg = calloc(1, sizeof(regex_t));
7198 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007199 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007200 return -1;
7201 }
7202
7203 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7204 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007205 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7206 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007207 if (curproxy == &defproxy) {
7208 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7209 return -1;
7210 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007211
7212 if (*(args[1]) == 0) {
7213 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7214 return -1;
7215 }
7216
7217 preg = calloc(1, sizeof(regex_t));
7218 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7219 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7220 return -1;
7221 }
7222
7223 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7224 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007225 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7226 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007227 if (curproxy == &defproxy) {
7228 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7229 return -1;
7230 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007231
7232 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007233 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007234 return -1;
7235 }
7236
7237 preg = calloc(1, sizeof(regex_t));
7238 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007239 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007240 return -1;
7241 }
7242
7243 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7244 }
7245 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7246 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007247 if (curproxy == &defproxy) {
7248 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7249 return -1;
7250 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007251
7252 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007253 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7254 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007255 return -1;
7256 }
7257
7258 preg = calloc(1, sizeof(regex_t));
7259 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007260 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007261 return -1;
7262 }
7263
willy tarreauc1f47532005-12-18 01:08:26 +01007264 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7265 if (err) {
7266 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7267 file, linenum, *err);
7268 return -1;
7269 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007270 }
7271 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
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 | REG_ICASE) != 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_REMOVE, NULL);
7290 }
7291 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this 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) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007299 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007300 return -1;
7301 }
7302
7303 preg = calloc(1, sizeof(regex_t));
7304 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007305 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007306 return -1;
7307 }
7308
7309 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7310 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007311 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7312 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007313 if (curproxy == &defproxy) {
7314 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7315 return -1;
7316 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007317
7318 if (*(args[1]) == 0) {
7319 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7320 return -1;
7321 }
7322
7323 preg = calloc(1, sizeof(regex_t));
7324 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7325 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7326 return -1;
7327 }
7328
7329 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7330 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007331 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7332 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007333 if (curproxy == &defproxy) {
7334 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7335 return -1;
7336 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007337
7338 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007339 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007340 return -1;
7341 }
7342
7343 preg = calloc(1, sizeof(regex_t));
7344 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007345 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007346 return -1;
7347 }
7348
7349 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7350 }
7351 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007352 if (curproxy == &defproxy) {
7353 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7354 return -1;
7355 }
7356
willy tarreau9fe663a2005-12-17 13:02:59 +01007357 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007358 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007359 return 0;
7360 }
7361
7362 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007363 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007364 return -1;
7365 }
7366
willy tarreau4302f492005-12-18 01:00:37 +01007367 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7368 }
7369 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7370 regex_t *preg;
7371
7372 if (*(args[1]) == 0 || *(args[2]) == 0) {
7373 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7374 file, linenum, args[0]);
7375 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007376 }
willy tarreau4302f492005-12-18 01:00:37 +01007377
7378 preg = calloc(1, sizeof(regex_t));
7379 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7380 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7381 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007382 }
willy tarreau4302f492005-12-18 01:00:37 +01007383
willy tarreauc1f47532005-12-18 01:08:26 +01007384 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7385 if (err) {
7386 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7387 file, linenum, *err);
7388 return -1;
7389 }
willy tarreau4302f492005-12-18 01:00:37 +01007390 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007391 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7392 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007393 if (curproxy == &defproxy) {
7394 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7395 return -1;
7396 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007397
7398 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007399 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007400 return -1;
7401 }
willy tarreaue39cd132005-12-17 13:00:18 +01007402
willy tarreau9fe663a2005-12-17 13:02:59 +01007403 preg = calloc(1, sizeof(regex_t));
7404 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007405 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007406 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007407 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007408
willy tarreauc1f47532005-12-18 01:08:26 +01007409 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7410 if (err) {
7411 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7412 file, linenum, *err);
7413 return -1;
7414 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007415 }
willy tarreau982249e2005-12-18 00:57:06 +01007416 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7417 regex_t *preg;
7418 if (curproxy == &defproxy) {
7419 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7420 return -1;
7421 }
7422
7423 if (*(args[1]) == 0) {
7424 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7425 return -1;
7426 }
7427
7428 preg = calloc(1, sizeof(regex_t));
7429 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7430 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7431 return -1;
7432 }
7433
willy tarreauc1f47532005-12-18 01:08:26 +01007434 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7435 if (err) {
7436 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7437 file, linenum, *err);
7438 return -1;
7439 }
willy tarreau982249e2005-12-18 00:57:06 +01007440 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007441 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007442 regex_t *preg;
7443 if (curproxy == &defproxy) {
7444 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7445 return -1;
7446 }
willy tarreaue39cd132005-12-17 13:00:18 +01007447
willy tarreaua41a8b42005-12-17 14:02:24 +01007448 if (*(args[1]) == 0 || *(args[2]) == 0) {
7449 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7450 file, linenum, args[0]);
7451 return -1;
7452 }
willy tarreaue39cd132005-12-17 13:00:18 +01007453
willy tarreaua41a8b42005-12-17 14:02:24 +01007454 preg = calloc(1, sizeof(regex_t));
7455 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7456 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7457 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007458 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007459
willy tarreauc1f47532005-12-18 01:08:26 +01007460 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7461 if (err) {
7462 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7463 file, linenum, *err);
7464 return -1;
7465 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007466 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007467 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7468 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007469 if (curproxy == &defproxy) {
7470 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7471 return -1;
7472 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007473
7474 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007475 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007476 return -1;
7477 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007478
willy tarreau9fe663a2005-12-17 13:02:59 +01007479 preg = calloc(1, sizeof(regex_t));
7480 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007481 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007482 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007483 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007484
willy tarreauc1f47532005-12-18 01:08:26 +01007485 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7486 if (err) {
7487 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7488 file, linenum, *err);
7489 return -1;
7490 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007491 }
willy tarreau982249e2005-12-18 00:57:06 +01007492 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7493 regex_t *preg;
7494 if (curproxy == &defproxy) {
7495 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7496 return -1;
7497 }
7498
7499 if (*(args[1]) == 0) {
7500 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7501 return -1;
7502 }
7503
7504 preg = calloc(1, sizeof(regex_t));
7505 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7506 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7507 return -1;
7508 }
7509
willy tarreauc1f47532005-12-18 01:08:26 +01007510 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7511 if (err) {
7512 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7513 file, linenum, *err);
7514 return -1;
7515 }
willy tarreau982249e2005-12-18 00:57:06 +01007516 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007517 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007518 if (curproxy == &defproxy) {
7519 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7520 return -1;
7521 }
7522
willy tarreau9fe663a2005-12-17 13:02:59 +01007523 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007524 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007525 return 0;
7526 }
7527
7528 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007529 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007530 return -1;
7531 }
7532
7533 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7534 }
willy tarreauc1f47532005-12-18 01:08:26 +01007535 else if (!strcmp(args[0], "errorloc") ||
7536 !strcmp(args[0], "errorloc302") ||
7537 !strcmp(args[0], "errorloc303")) { /* error location */
7538 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007539 char *err;
7540
willy tarreaueedaa9f2005-12-17 14:08:03 +01007541 // if (curproxy == &defproxy) {
7542 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7543 // return -1;
7544 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007545
willy tarreau8337c6b2005-12-17 13:41:01 +01007546 if (*(args[2]) == 0) {
7547 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7548 return -1;
7549 }
7550
7551 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007552 if (!strcmp(args[0], "errorloc303")) {
7553 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7554 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7555 } else {
7556 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7557 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7558 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007559
7560 if (errnum == 400) {
7561 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007562 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007563 free(curproxy->errmsg.msg400);
7564 }
7565 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007566 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007567 }
7568 else if (errnum == 403) {
7569 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007570 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007571 free(curproxy->errmsg.msg403);
7572 }
7573 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007574 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007575 }
7576 else if (errnum == 408) {
7577 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007578 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007579 free(curproxy->errmsg.msg408);
7580 }
7581 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007582 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007583 }
7584 else if (errnum == 500) {
7585 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007586 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007587 free(curproxy->errmsg.msg500);
7588 }
7589 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007590 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007591 }
7592 else if (errnum == 502) {
7593 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007594 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007595 free(curproxy->errmsg.msg502);
7596 }
7597 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007598 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007599 }
7600 else if (errnum == 503) {
7601 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007602 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007603 free(curproxy->errmsg.msg503);
7604 }
7605 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007606 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007607 }
7608 else if (errnum == 504) {
7609 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007610 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007611 free(curproxy->errmsg.msg504);
7612 }
7613 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007614 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007615 }
7616 else {
7617 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7618 free(err);
7619 }
7620 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007621 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007622 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007623 return -1;
7624 }
7625 return 0;
7626}
willy tarreaue39cd132005-12-17 13:00:18 +01007627
willy tarreau5cbea6f2005-12-17 12:48:26 +01007628
willy tarreau9fe663a2005-12-17 13:02:59 +01007629/*
7630 * This function reads and parses the configuration file given in the argument.
7631 * returns 0 if OK, -1 if error.
7632 */
7633int readcfgfile(char *file) {
7634 char thisline[256];
7635 char *line;
7636 FILE *f;
7637 int linenum = 0;
7638 char *end;
7639 char *args[MAX_LINE_ARGS];
7640 int arg;
7641 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007642 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007643 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007644
willy tarreau9fe663a2005-12-17 13:02:59 +01007645 struct proxy *curproxy = NULL;
7646 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007647
willy tarreau9fe663a2005-12-17 13:02:59 +01007648 if ((f=fopen(file,"r")) == NULL)
7649 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007650
willy tarreaueedaa9f2005-12-17 14:08:03 +01007651 init_default_instance();
7652
willy tarreau9fe663a2005-12-17 13:02:59 +01007653 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7654 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007655
willy tarreau9fe663a2005-12-17 13:02:59 +01007656 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007657
willy tarreau9fe663a2005-12-17 13:02:59 +01007658 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007659 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007660 line++;
7661
7662 arg = 0;
7663 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007664
willy tarreau9fe663a2005-12-17 13:02:59 +01007665 while (*line && arg < MAX_LINE_ARGS) {
7666 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7667 * C equivalent value. Other combinations left unchanged (eg: \1).
7668 */
7669 if (*line == '\\') {
7670 int skip = 0;
7671 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7672 *line = line[1];
7673 skip = 1;
7674 }
7675 else if (line[1] == 'r') {
7676 *line = '\r';
7677 skip = 1;
7678 }
7679 else if (line[1] == 'n') {
7680 *line = '\n';
7681 skip = 1;
7682 }
7683 else if (line[1] == 't') {
7684 *line = '\t';
7685 skip = 1;
7686 }
willy tarreauc1f47532005-12-18 01:08:26 +01007687 else if (line[1] == 'x') {
7688 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7689 unsigned char hex1, hex2;
7690 hex1 = toupper(line[2]) - '0';
7691 hex2 = toupper(line[3]) - '0';
7692 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7693 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7694 *line = (hex1<<4) + hex2;
7695 skip = 3;
7696 }
7697 else {
7698 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7699 return -1;
7700 }
7701 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007702 if (skip) {
7703 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7704 end -= skip;
7705 }
7706 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007707 }
willy tarreaua1598082005-12-17 13:08:06 +01007708 else if (*line == '#' || *line == '\n' || *line == '\r') {
7709 /* end of string, end of loop */
7710 *line = 0;
7711 break;
7712 }
willy tarreauc29948c2005-12-17 13:10:27 +01007713 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007714 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007715 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007716 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007717 line++;
7718 args[++arg] = line;
7719 }
7720 else {
7721 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007722 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007723 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007724
willy tarreau9fe663a2005-12-17 13:02:59 +01007725 /* empty line */
7726 if (!**args)
7727 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007728
willy tarreau9fe663a2005-12-17 13:02:59 +01007729 /* zero out remaining args */
7730 while (++arg < MAX_LINE_ARGS) {
7731 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007732 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007733
willy tarreaua41a8b42005-12-17 14:02:24 +01007734 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007735 confsect = CFG_LISTEN;
7736 else if (!strcmp(args[0], "global")) /* global config */
7737 confsect = CFG_GLOBAL;
7738 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007739
willy tarreau9fe663a2005-12-17 13:02:59 +01007740 switch (confsect) {
7741 case CFG_LISTEN:
7742 if (cfg_parse_listen(file, linenum, args) < 0)
7743 return -1;
7744 break;
7745 case CFG_GLOBAL:
7746 if (cfg_parse_global(file, linenum, args) < 0)
7747 return -1;
7748 break;
7749 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007750 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007751 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007752 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007753
7754
willy tarreau0f7af912005-12-17 12:21:26 +01007755 }
7756 fclose(f);
7757
7758 /*
7759 * Now, check for the integrity of all that we have collected.
7760 */
7761
Willy TARREAU3759f982006-03-01 22:44:17 +01007762 /* will be needed further to delay some tasks */
7763 tv_now(&now);
7764
willy tarreau0f7af912005-12-17 12:21:26 +01007765 if ((curproxy = proxy) == NULL) {
7766 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7767 file);
7768 return -1;
7769 }
7770
7771 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007772 curproxy->cursrv = NULL;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007773 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007774 curproxy = curproxy->next;
7775 continue;
7776 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007777
7778 if (curproxy->listen == NULL) {
7779 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);
7780 cfgerr++;
7781 }
7782 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007783 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007784 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007785 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7786 file, curproxy->id);
7787 cfgerr++;
7788 }
7789 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7790 if (curproxy->options & PR_O_TRANSP) {
7791 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7792 file, curproxy->id);
7793 cfgerr++;
7794 }
7795 else if (curproxy->srv == NULL) {
7796 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7797 file, curproxy->id);
7798 cfgerr++;
7799 }
willy tarreaua1598082005-12-17 13:08:06 +01007800 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007801 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7802 file, curproxy->id);
7803 }
7804 }
7805 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007806 if (curproxy->cookie_name != NULL) {
7807 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7808 file, curproxy->id);
7809 }
7810 if ((newsrv = curproxy->srv) != NULL) {
7811 Warning("parsing %s : servers will be ignored for listener %s.\n",
7812 file, curproxy->id);
7813 }
willy tarreaue39cd132005-12-17 13:00:18 +01007814 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007815 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7816 file, curproxy->id);
7817 }
willy tarreaue39cd132005-12-17 13:00:18 +01007818 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007819 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7820 file, curproxy->id);
7821 }
7822 }
7823 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7824 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7825 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7826 file, curproxy->id);
7827 cfgerr++;
7828 }
7829 else {
7830 while (newsrv != NULL) {
7831 /* nothing to check for now */
7832 newsrv = newsrv->next;
7833 }
7834 }
7835 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007836
7837 if (curproxy->options & PR_O_LOGASAP)
7838 curproxy->to_log &= ~LW_BYTES;
7839
willy tarreau8337c6b2005-12-17 13:41:01 +01007840 if (curproxy->errmsg.msg400 == NULL) {
7841 curproxy->errmsg.msg400 = (char *)HTTP_400;
7842 curproxy->errmsg.len400 = strlen(HTTP_400);
7843 }
7844 if (curproxy->errmsg.msg403 == NULL) {
7845 curproxy->errmsg.msg403 = (char *)HTTP_403;
7846 curproxy->errmsg.len403 = strlen(HTTP_403);
7847 }
7848 if (curproxy->errmsg.msg408 == NULL) {
7849 curproxy->errmsg.msg408 = (char *)HTTP_408;
7850 curproxy->errmsg.len408 = strlen(HTTP_408);
7851 }
7852 if (curproxy->errmsg.msg500 == NULL) {
7853 curproxy->errmsg.msg500 = (char *)HTTP_500;
7854 curproxy->errmsg.len500 = strlen(HTTP_500);
7855 }
7856 if (curproxy->errmsg.msg502 == NULL) {
7857 curproxy->errmsg.msg502 = (char *)HTTP_502;
7858 curproxy->errmsg.len502 = strlen(HTTP_502);
7859 }
7860 if (curproxy->errmsg.msg503 == NULL) {
7861 curproxy->errmsg.msg503 = (char *)HTTP_503;
7862 curproxy->errmsg.len503 = strlen(HTTP_503);
7863 }
7864 if (curproxy->errmsg.msg504 == NULL) {
7865 curproxy->errmsg.msg504 = (char *)HTTP_504;
7866 curproxy->errmsg.len504 = strlen(HTTP_504);
7867 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007868
7869 /* now we'll start this proxy's health checks if any */
7870 /* 1- count the checkers to run simultaneously */
7871 nbchk = 0;
7872 mininter = 0;
7873 newsrv = curproxy->srv;
7874 while (newsrv != NULL) {
7875 if (newsrv->state & SRV_CHECKED) {
7876 if (!mininter || mininter > newsrv->inter)
7877 mininter = newsrv->inter;
7878 nbchk++;
7879 }
7880 newsrv = newsrv->next;
7881 }
7882
7883 /* 2- start them as far as possible from each others while respecting
7884 * their own intervals. For this, we will start them after their own
7885 * interval added to the min interval divided by the number of servers,
7886 * weighted by the server's position in the list.
7887 */
7888 if (nbchk > 0) {
7889 struct task *t;
7890 int srvpos;
7891
7892 newsrv = curproxy->srv;
7893 srvpos = 0;
7894 while (newsrv != NULL) {
7895 /* should this server be checked ? */
7896 if (newsrv->state & SRV_CHECKED) {
7897 if ((t = pool_alloc(task)) == NULL) {
7898 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7899 return -1;
7900 }
7901
7902 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
7903 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
7904 t->state = TASK_IDLE;
7905 t->process = process_chk;
7906 t->context = newsrv;
7907
7908 /* check this every ms */
7909 tv_delayfrom(&t->expire, &now,
7910 newsrv->inter + mininter * srvpos / nbchk);
7911 task_queue(t);
7912 //task_wakeup(&rq, t);
7913 srvpos++;
7914 }
7915 newsrv = newsrv->next;
7916 }
7917 }
7918
willy tarreau0f7af912005-12-17 12:21:26 +01007919 curproxy = curproxy->next;
7920 }
7921 if (cfgerr > 0) {
7922 Alert("Errors found in configuration file, aborting.\n");
7923 return -1;
7924 }
7925 else
7926 return 0;
7927}
7928
7929
7930/*
7931 * This function initializes all the necessary variables. It only returns
7932 * if everything is OK. If something fails, it exits.
7933 */
7934void init(int argc, char **argv) {
7935 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007936 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007937 char *old_argv = *argv;
7938 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007939 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007940
7941 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007942 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007943 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007944 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007945 exit(1);
7946 }
7947
Willy TARREAUa9e75f62006-03-01 22:27:48 +01007948 /* initialize the libc's localtime structures once for all so that we
7949 * won't be missing memory if we want to send alerts under OOM conditions.
7950 */
7951 tv_now(&now);
7952 localtime(&now.tv_sec);
7953
willy tarreau4302f492005-12-18 01:00:37 +01007954 /* initialize the log header encoding map : '{|}"#' should be encoded with
7955 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7956 * URL encoding only requires '"', '#' to be encoded as well as non-
7957 * printable characters above.
7958 */
7959 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7960 memset(url_encode_map, 0, sizeof(url_encode_map));
7961 for (i = 0; i < 32; i++) {
7962 FD_SET(i, hdr_encode_map);
7963 FD_SET(i, url_encode_map);
7964 }
7965 for (i = 127; i < 256; i++) {
7966 FD_SET(i, hdr_encode_map);
7967 FD_SET(i, url_encode_map);
7968 }
7969
7970 tmp = "\"#{|}";
7971 while (*tmp) {
7972 FD_SET(*tmp, hdr_encode_map);
7973 tmp++;
7974 }
7975
7976 tmp = "\"#";
7977 while (*tmp) {
7978 FD_SET(*tmp, url_encode_map);
7979 tmp++;
7980 }
7981
willy tarreau64a3cc32005-12-18 01:13:11 +01007982 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
7983#if defined(ENABLE_POLL)
7984 cfg_polling_mechanism |= POLL_USE_POLL;
7985#endif
7986#if defined(ENABLE_EPOLL)
7987 cfg_polling_mechanism |= POLL_USE_EPOLL;
7988#endif
7989
willy tarreau0f7af912005-12-17 12:21:26 +01007990 pid = getpid();
7991 progname = *argv;
7992 while ((tmp = strchr(progname, '/')) != NULL)
7993 progname = tmp + 1;
7994
7995 argc--; argv++;
7996 while (argc > 0) {
7997 char *flag;
7998
7999 if (**argv == '-') {
8000 flag = *argv+1;
8001
8002 /* 1 arg */
8003 if (*flag == 'v') {
8004 display_version();
8005 exit(0);
8006 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008007#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008008 else if (*flag == 'd' && flag[1] == 'e')
8009 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008010#endif
8011#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008012 else if (*flag == 'd' && flag[1] == 'p')
8013 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008014#endif
willy tarreau982249e2005-12-18 00:57:06 +01008015 else if (*flag == 'V')
8016 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01008017 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008018 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008019 else if (*flag == 'c')
8020 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008021 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008022 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008023 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008024 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01008025#if STATTIME > 0
8026 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01008027 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01008028 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01008029 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01008030#endif
8031 else { /* >=2 args */
8032 argv++; argc--;
8033 if (argc == 0)
8034 usage(old_argv);
8035
8036 switch (*flag) {
8037 case 'n' : cfg_maxconn = atol(*argv); break;
8038 case 'N' : cfg_maxpconn = atol(*argv); break;
8039 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008040 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008041 default: usage(old_argv);
8042 }
8043 }
8044 }
8045 else
8046 usage(old_argv);
8047 argv++; argc--;
8048 }
8049
willy tarreaud0fb4652005-12-18 01:32:04 +01008050 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
8051 (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008052
willy tarreau0f7af912005-12-17 12:21:26 +01008053 if (!cfg_cfgfile)
8054 usage(old_argv);
8055
8056 gethostname(hostname, MAX_HOSTNAME_LEN);
8057
willy tarreau12350152005-12-18 01:03:27 +01008058 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008059 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008060 if (readcfgfile(cfg_cfgfile) < 0) {
8061 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8062 exit(1);
8063 }
willy tarreau12350152005-12-18 01:03:27 +01008064 if (have_appsession)
8065 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008066
willy tarreau982249e2005-12-18 00:57:06 +01008067 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008068 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8069 exit(0);
8070 }
8071
willy tarreau9fe663a2005-12-17 13:02:59 +01008072 if (cfg_maxconn > 0)
8073 global.maxconn = cfg_maxconn;
8074
willy tarreaufe2c5c12005-12-17 14:14:34 +01008075 if (cfg_pidfile) {
8076 if (global.pidfile)
8077 free(global.pidfile);
8078 global.pidfile = strdup(cfg_pidfile);
8079 }
8080
willy tarreau9fe663a2005-12-17 13:02:59 +01008081 if (global.maxconn == 0)
8082 global.maxconn = DEFAULT_MAXCONN;
8083
Willy TARREAU203b0b62006-03-12 18:00:28 +01008084 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008085
8086 if (arg_mode & MODE_DEBUG) {
8087 /* command line debug mode inhibits configuration mode */
8088 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8089 }
willy tarreau982249e2005-12-18 00:57:06 +01008090 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
8091 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008092
8093 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8094 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8095 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8096 }
8097
8098 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
8099 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
8100 global.nbproc = 1;
8101 }
8102
8103 if (global.nbproc < 1)
8104 global.nbproc = 1;
8105
willy tarreau0f7af912005-12-17 12:21:26 +01008106 StaticReadEvent = (fd_set *)calloc(1,
8107 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008108 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008109 StaticWriteEvent = (fd_set *)calloc(1,
8110 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008111 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008112
8113 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008114 sizeof(struct fdtab) * (global.maxsock));
8115 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008116 fdtab[i].state = FD_STCLOSE;
8117 }
8118}
8119
8120/*
8121 * this function starts all the proxies. It returns 0 if OK, -1 if not.
8122 */
8123int start_proxies() {
8124 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008125 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01008126 int fd;
8127
8128 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01008129 if (curproxy->state == PR_STSTOPPED)
willy tarreau0f7af912005-12-17 12:21:26 +01008130 continue;
8131
willy tarreaua41a8b42005-12-17 14:02:24 +01008132 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
8133 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01008134 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008135 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8136 curproxy->id);
8137 return -1;
8138 }
willy tarreau0f7af912005-12-17 12:21:26 +01008139
willy tarreaua41a8b42005-12-17 14:02:24 +01008140 if (fd >= global.maxsock) {
8141 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
8142 curproxy->id);
8143 close(fd);
8144 return -1;
8145 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008146
willy tarreaua41a8b42005-12-17 14:02:24 +01008147 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
8148 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
8149 (char *) &one, sizeof(one)) == -1)) {
8150 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
8151 curproxy->id);
8152 close(fd);
8153 return -1;
8154 }
willy tarreau0f7af912005-12-17 12:21:26 +01008155
willy tarreaua41a8b42005-12-17 14:02:24 +01008156 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8157 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8158 curproxy->id);
8159 }
willy tarreau0f7af912005-12-17 12:21:26 +01008160
willy tarreaua41a8b42005-12-17 14:02:24 +01008161 if (bind(fd,
8162 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008163 listener->addr.ss_family == AF_INET6 ?
8164 sizeof(struct sockaddr_in6) :
8165 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008166 Alert("cannot bind socket for proxy %s. Aborting.\n",
8167 curproxy->id);
8168 close(fd);
8169 return -1;
8170 }
willy tarreau0f7af912005-12-17 12:21:26 +01008171
willy tarreaua41a8b42005-12-17 14:02:24 +01008172 if (listen(fd, curproxy->maxconn) == -1) {
8173 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8174 curproxy->id);
8175 close(fd);
8176 return -1;
8177 }
willy tarreau0f7af912005-12-17 12:21:26 +01008178
willy tarreaua41a8b42005-12-17 14:02:24 +01008179 /* the function for the accept() event */
8180 fdtab[fd].read = &event_accept;
8181 fdtab[fd].write = NULL; /* never called */
8182 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
8183 curproxy->state = PR_STRUN;
8184 fdtab[fd].state = FD_STLISTEN;
8185 FD_SET(fd, StaticReadEvent);
8186 fd_insert(fd);
8187 listeners++;
8188 }
willy tarreaua1598082005-12-17 13:08:06 +01008189 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01008190 }
8191 return 0;
8192}
8193
willy tarreaub952e1d2005-12-18 01:31:20 +01008194int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008195
8196 appsess *temp1,*temp2;
8197 temp1 = (appsess *)key1;
8198 temp2 = (appsess *)key2;
8199
8200 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8201 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8202
8203 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8204}/* end match_str */
8205
willy tarreaub952e1d2005-12-18 01:31:20 +01008206void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008207 appsess *temp1;
8208
8209 //printf("destroy called\n");
8210 temp1 = (appsess *)data;
8211
8212 if (temp1->sessid)
8213 pool_free_to(apools.sessid, temp1->sessid);
8214
8215 if (temp1->serverid)
8216 pool_free_to(apools.serverid, temp1->serverid);
8217
8218 pool_free(appsess, temp1);
8219} /* end destroy */
8220
8221void appsession_cleanup( void )
8222{
8223 struct proxy *p = proxy;
8224
8225 while(p) {
8226 chtbl_destroy(&(p->htbl_proxy));
8227 p = p->next;
8228 }
8229}/* end appsession_cleanup() */
8230
8231void pool_destroy(void **pool)
8232{
8233 void *temp, *next;
8234 next = pool;
8235 while (next) {
8236 temp = next;
8237 next = *(void **)temp;
8238 free(temp);
8239 }
8240}/* end pool_destroy() */
8241
willy tarreaub952e1d2005-12-18 01:31:20 +01008242void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008243 struct proxy *p = proxy;
8244 struct cap_hdr *h,*h_next;
8245 struct server *s,*s_next;
8246 struct listener *l,*l_next;
8247
8248 while (p) {
8249 if (p->id)
8250 free(p->id);
8251
8252 if (p->check_req)
8253 free(p->check_req);
8254
8255 if (p->cookie_name)
8256 free(p->cookie_name);
8257
8258 if (p->capture_name)
8259 free(p->capture_name);
8260
8261 /* only strup if the user have set in config.
8262 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008263 if (p->errmsg.msg400) free(p->errmsg.msg400);
8264 if (p->errmsg.msg403) free(p->errmsg.msg403);
8265 if (p->errmsg.msg408) free(p->errmsg.msg408);
8266 if (p->errmsg.msg500) free(p->errmsg.msg500);
8267 if (p->errmsg.msg502) free(p->errmsg.msg502);
8268 if (p->errmsg.msg503) free(p->errmsg.msg503);
8269 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008270 */
8271 if (p->appsession_name)
8272 free(p->appsession_name);
8273
8274 h = p->req_cap;
8275 while (h) {
8276 h_next = h->next;
8277 if (h->name)
8278 free(h->name);
8279 pool_destroy(h->pool);
8280 free(h);
8281 h = h_next;
8282 }/* end while(h) */
8283
8284 h = p->rsp_cap;
8285 while (h) {
8286 h_next = h->next;
8287 if (h->name)
8288 free(h->name);
8289
8290 pool_destroy(h->pool);
8291 free(h);
8292 h = h_next;
8293 }/* end while(h) */
8294
8295 s = p->srv;
8296 while (s) {
8297 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008298 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008299 free(s->id);
8300
willy tarreaub952e1d2005-12-18 01:31:20 +01008301 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008302 free(s->cookie);
8303
8304 free(s);
8305 s = s_next;
8306 }/* end while(s) */
8307
8308 l = p->listen;
8309 while (l) {
8310 l_next = l->next;
8311 free(l);
8312 l = l_next;
8313 }/* end while(l) */
8314
8315 pool_destroy((void **) p->req_cap_pool);
8316 pool_destroy((void **) p->rsp_cap_pool);
8317 p = p->next;
8318 }/* end while(p) */
8319
8320 if (global.chroot) free(global.chroot);
8321 if (global.pidfile) free(global.pidfile);
8322
willy tarreau12350152005-12-18 01:03:27 +01008323 if (StaticReadEvent) free(StaticReadEvent);
8324 if (StaticWriteEvent) free(StaticWriteEvent);
8325 if (fdtab) free(fdtab);
8326
8327 pool_destroy(pool_session);
8328 pool_destroy(pool_buffer);
8329 pool_destroy(pool_fdtab);
8330 pool_destroy(pool_requri);
8331 pool_destroy(pool_task);
8332 pool_destroy(pool_capture);
8333 pool_destroy(pool_appsess);
8334
8335 if (have_appsession) {
8336 pool_destroy(apools.serverid);
8337 pool_destroy(apools.sessid);
8338 }
8339} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008340
8341int main(int argc, char **argv) {
willy tarreaub1285d52005-12-18 01:20:14 +01008342 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008343 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008344 init(argc, argv);
8345
willy tarreau0f7af912005-12-17 12:21:26 +01008346 signal(SIGQUIT, dump);
8347 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008348 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008349#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008350 signal(SIGINT, sig_int);
8351 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008352#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008353
8354 /* on very high loads, a sigpipe sometimes happen just between the
8355 * getsockopt() which tells "it's OK to write", and the following write :-(
8356 */
willy tarreau3242e862005-12-17 12:27:53 +01008357#ifndef MSG_NOSIGNAL
8358 signal(SIGPIPE, SIG_IGN);
8359#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008360
willy tarreaud0fb4652005-12-18 01:32:04 +01008361 /* start_proxies() sends an alert when it fails. */
willy tarreau0f7af912005-12-17 12:21:26 +01008362 if (start_proxies() < 0)
8363 exit(1);
willy tarreaud0fb4652005-12-18 01:32:04 +01008364
8365 if (listeners == 0) {
8366 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
8367 exit(1);
8368 }
8369
willy tarreaudbd3bef2006-01-20 19:35:18 +01008370 /* prepare pause/play signals */
8371 signal(SIGTTOU, sig_pause);
8372 signal(SIGTTIN, sig_listen);
8373
Willy TARREAUe3283d12006-03-01 22:15:29 +01008374 if (global.mode & MODE_DAEMON) {
8375 global.mode &= ~MODE_VERBOSE;
8376 global.mode |= MODE_QUIET;
8377 }
8378
willy tarreaud0fb4652005-12-18 01:32:04 +01008379 /* MODE_QUIET can inhibit alerts and warnings below this line */
8380
8381 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008382 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008383 /* detach from the tty */
8384 fclose(stdin); fclose(stdout); fclose(stderr);
8385 close(0); close(1); close(2);
8386 }
willy tarreau0f7af912005-12-17 12:21:26 +01008387
willy tarreaufe2c5c12005-12-17 14:14:34 +01008388 /* open log & pid files before the chroot */
8389 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8390 int pidfd;
8391 unlink(global.pidfile);
8392 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8393 if (pidfd < 0) {
8394 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
8395 exit(1);
8396 }
8397 pidfile = fdopen(pidfd, "w");
8398 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008399
8400 /* chroot if needed */
8401 if (global.chroot != NULL) {
8402 if (chroot(global.chroot) == -1) {
8403 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
8404 exit(1);
8405 }
8406 chdir("/");
8407 }
8408
willy tarreaub1285d52005-12-18 01:20:14 +01008409 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01008410 if (!global.rlimit_nofile)
8411 global.rlimit_nofile = global.maxsock;
8412
willy tarreaub1285d52005-12-18 01:20:14 +01008413 if (global.rlimit_nofile) {
8414 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8415 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8416 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8417 }
8418 }
8419
willy tarreau9fe663a2005-12-17 13:02:59 +01008420 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008421 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008422 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8423 exit(1);
8424 }
8425
willy tarreau036e1ce2005-12-17 13:46:33 +01008426 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008427 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8428 exit(1);
8429 }
8430
willy tarreaub1285d52005-12-18 01:20:14 +01008431 /* check ulimits */
8432 limit.rlim_cur = limit.rlim_max = 0;
8433 getrlimit(RLIMIT_NOFILE, &limit);
8434 if (limit.rlim_cur < global.maxsock) {
8435 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",
8436 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8437 }
8438
willy tarreau9fe663a2005-12-17 13:02:59 +01008439 if (global.mode & MODE_DAEMON) {
8440 int ret = 0;
8441 int proc;
8442
8443 /* the father launches the required number of processes */
8444 for (proc = 0; proc < global.nbproc; proc++) {
8445 ret = fork();
8446 if (ret < 0) {
8447 Alert("[%s.main()] Cannot fork.\n", argv[0]);
8448 exit(1); /* there has been an error */
8449 }
8450 else if (ret == 0) /* child breaks here */
8451 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008452 if (pidfile != NULL) {
8453 fprintf(pidfile, "%d\n", ret);
8454 fflush(pidfile);
8455 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008456 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008457 /* close the pidfile both in children and father */
8458 if (pidfile != NULL)
8459 fclose(pidfile);
8460 free(global.pidfile);
8461
willy tarreau9fe663a2005-12-17 13:02:59 +01008462 if (proc == global.nbproc)
8463 exit(0); /* parent must leave */
8464
willy tarreau750a4722005-12-17 13:21:24 +01008465 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8466 * that we can detach from the TTY. We MUST NOT do it in other cases since
8467 * it would have already be done, and 0-2 would have been affected to listening
8468 * sockets
8469 */
8470 if (!(global.mode & MODE_QUIET)) {
8471 /* detach from the tty */
8472 fclose(stdin); fclose(stdout); fclose(stderr);
8473 close(0); close(1); close(2); /* close all fd's */
8474 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8475 }
willy tarreaua1598082005-12-17 13:08:06 +01008476 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008477 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008478 }
8479
willy tarreau1c2ad212005-12-18 01:11:29 +01008480#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008481 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008482 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8483 epoll_loop(POLL_LOOP_ACTION_RUN);
8484 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008485 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008486 }
8487 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008488 Warning("epoll() is not available. Using poll()/select() instead.\n");
8489 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008490 }
8491 }
8492#endif
8493
8494#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008495 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008496 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8497 poll_loop(POLL_LOOP_ACTION_RUN);
8498 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008499 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008500 }
8501 else {
8502 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008503 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008504 }
8505 }
8506#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008507 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008508 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8509 select_loop(POLL_LOOP_ACTION_RUN);
8510 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008511 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008512 }
8513 }
8514
willy tarreau0f7af912005-12-17 12:21:26 +01008515
willy tarreau12350152005-12-18 01:03:27 +01008516 /* Free all Hash Keys and all Hash elements */
8517 appsession_cleanup();
8518 /* Do some cleanup */
8519 deinit();
8520
willy tarreau0f7af912005-12-17 12:21:26 +01008521 exit(0);
8522}
willy tarreau12350152005-12-18 01:03:27 +01008523
8524#if defined(DEBUG_HASH)
8525static void print_table(const CHTbl *htbl) {
8526
8527 ListElmt *element;
8528 int i;
8529 appsess *asession;
8530
8531 /*****************************************************************************
8532 * *
8533 * Display the chained hash table. *
8534 * *
8535 *****************************************************************************/
8536
8537 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8538
8539 for (i = 0; i < TBLSIZ; i++) {
8540 fprintf(stdout, "Bucket[%03d]\n", i);
8541
8542 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8543 //fprintf(stdout, "%c", *(char *)list_data(element));
8544 asession = (appsess *)list_data(element);
8545 fprintf(stdout, "ELEM :%s:", asession->sessid);
8546 fprintf(stdout, " Server :%s: \n", asession->serverid);
8547 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8548 }
8549
8550 fprintf(stdout, "\n");
8551 }
8552 return;
8553} /* end print_table */
8554#endif
8555
8556static int appsession_init(void)
8557{
8558 static int initialized = 0;
8559 int idlen;
8560 struct server *s;
8561 struct proxy *p = proxy;
8562
8563 if (!initialized) {
8564 if (!appsession_task_init()) {
8565 apools.sessid = NULL;
8566 apools.serverid = NULL;
8567 apools.ser_waste = 0;
8568 apools.ser_use = 0;
8569 apools.ser_msize = sizeof(void *);
8570 apools.ses_waste = 0;
8571 apools.ses_use = 0;
8572 apools.ses_msize = sizeof(void *);
8573 while (p) {
8574 s = p->srv;
8575 if (apools.ses_msize < p->appsession_len)
8576 apools.ses_msize = p->appsession_len;
8577 while (s) {
8578 idlen = strlen(s->id);
8579 if (apools.ser_msize < idlen)
8580 apools.ser_msize = idlen;
8581 s = s->next;
8582 }
8583 p = p->next;
8584 }
8585 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8586 apools.ses_msize ++;
8587 }
8588 else {
8589 fprintf(stderr, "appsession_task_init failed\n");
8590 return -1;
8591 }
8592 initialized ++;
8593 }
8594 return 0;
8595}
8596
8597static int appsession_task_init(void)
8598{
8599 static int initialized = 0;
8600 struct task *t;
8601 if (!initialized) {
8602 if ((t = pool_alloc(task)) == NULL)
8603 return -1;
8604 t->next = t->prev = t->rqnext = NULL;
8605 t->wq = LIST_HEAD(wait_queue);
8606 t->state = TASK_IDLE;
8607 t->context = NULL;
8608 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8609 task_queue(t);
8610 t->process = appsession_refresh;
8611 initialized ++;
8612 }
8613 return 0;
8614}
8615
8616static int appsession_refresh(struct task *t) {
8617 struct proxy *p = proxy;
8618 CHTbl *htbl;
8619 ListElmt *element, *last;
8620 int i;
8621 appsess *asession;
8622 void *data;
8623
8624 while (p) {
8625 if (p->appsession_name != NULL) {
8626 htbl = &p->htbl_proxy;
8627 /* if we ever give up the use of TBLSIZ, we need to change this */
8628 for (i = 0; i < TBLSIZ; i++) {
8629 last = NULL;
8630 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8631 asession = (appsess *)list_data(element);
8632 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8633 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8634 int len;
8635 /*
8636 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8637 */
8638 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8639 asession->sessid, asession->serverid?asession->serverid:"(null)");
8640 write(1, trash, len);
8641 }
8642 /* delete the expired element from within the hash table */
8643 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8644 && (htbl->table[i].destroy != NULL)) {
8645 htbl->table[i].destroy(data);
8646 }
8647 if (last == NULL) {/* patient lost his head, get a new one */
8648 element = list_head(&htbl->table[i]);
8649 if (element == NULL) break; /* no heads left, go to next patient */
8650 }
8651 else
8652 element = last;
8653 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8654 else
8655 last = element;
8656 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8657 }
8658 }
8659 p = p->next;
8660 }
8661 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8662 return TBLCHKINT;
8663} /* end appsession_refresh */
8664