blob: c5af86a36a64d19f5f2c687a5d8f6404c767a183 [file] [log] [blame]
willy tarreau0f7af912005-12-17 12:21:26 +01001/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01002 * HA-Proxy : High Availability-enabled HTTP/TCP proxy
willy tarreau726618c2006-01-29 22:42:06 +01003 * 2000-2006 - Willy Tarreau - willy AT meta-x DOT org.
willy tarreau0f7af912005-12-17 12:21:26 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
willy tarreau906b2682005-12-17 13:49:52 +010010 * Please refer to RFC2068 or RFC2616 for informations about HTTP protocol, and
willy tarreau982249e2005-12-18 00:57:06 +010011 * RFC2965 for informations about cookies usage. More generally, the IETF HTTP
12 * Working Group's web site should be consulted for protocol related changes :
13 *
14 * http://ftp.ics.uci.edu/pub/ietf/http/
willy tarreau906b2682005-12-17 13:49:52 +010015 *
16 * Pending bugs (may be not fixed because never reproduced) :
willy tarreaua1598082005-12-17 13:08:06 +010017 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
18 * the proxy to terminate (no core) if the client breaks the connection during
willy tarreauc29948c2005-12-17 13:10:27 +010019 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
willy tarreau8337c6b2005-12-17 13:41:01 +010020 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
21 * related to missing setsid() (fixed in 1.1.15)
willy tarreauef900ab2005-12-17 12:52:52 +010022 * - a proxy with an invalid config will prevent the startup even if disabled.
23 *
willy tarreau036e1ce2005-12-17 13:46:33 +010024 * ChangeLog has moved to the CHANGELOG file.
willy tarreau0f7af912005-12-17 12:21:26 +010025 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010026 * TODO:
27 * - handle properly intermediate incomplete server headers. Done ?
willy tarreau5cbea6f2005-12-17 12:48:26 +010028 * - handle hot-reconfiguration
willy tarreau906b2682005-12-17 13:49:52 +010029 * - fix client/server state transition when server is in connect or headers state
30 * and client suddenly disconnects. The server *should* switch to SHUT_WR, but
31 * still handle HTTP headers.
willy tarreau4302f492005-12-18 01:00:37 +010032 * - remove MAX_NEWHDR
willy tarreauc1f47532005-12-18 01:08:26 +010033 * - cut this huge file into several ones
willy tarreau0f7af912005-12-17 12:21:26 +010034 *
35 */
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <unistd.h>
40#include <string.h>
41#include <ctype.h>
42#include <sys/time.h>
43#include <sys/types.h>
44#include <sys/socket.h>
45#include <netinet/tcp.h>
46#include <netinet/in.h>
47#include <arpa/inet.h>
48#include <netdb.h>
49#include <fcntl.h>
50#include <errno.h>
51#include <signal.h>
52#include <stdarg.h>
53#include <sys/resource.h>
54#include <time.h>
willy tarreau0f7af912005-12-17 12:21:26 +010055#include <syslog.h>
willy tarreau77bc8542005-12-18 01:31:43 +010056
57#ifdef USE_PCRE
58#include <pcre.h>
59#include <pcreposix.h>
60#else
61#include <regex.h>
62#endif
63
willy tarreaua1598082005-12-17 13:08:06 +010064#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +010065#include <linux/netfilter_ipv4.h>
66#endif
willy tarreau0f7af912005-12-17 12:21:26 +010067
willy tarreau12350152005-12-18 01:03:27 +010068#if defined(__dietlibc__)
69#include <strings.h>
70#endif
71
willy tarreau1c2ad212005-12-18 01:11:29 +010072#if defined(ENABLE_POLL)
73#include <sys/poll.h>
74#endif
75
76#if defined(ENABLE_EPOLL)
77#if !defined(USE_MY_EPOLL)
willy tarreauad90a0c2005-12-18 01:09:15 +010078#include <sys/epoll.h>
willy tarreau1c2ad212005-12-18 01:11:29 +010079#else
80#include "include/epoll.h"
81#endif
82#endif
willy tarreauad90a0c2005-12-18 01:09:15 +010083
willy tarreau779dc892006-03-19 19:32:29 +010084#ifdef DEBUG_FULL
85#include <assert.h>
86#endif
87
willy tarreau598da412005-12-18 01:07:29 +010088#include "include/appsession.h"
willy tarreau12350152005-12-18 01:03:27 +010089
willy tarreaubfad5742006-03-23 14:19:11 +010090#ifndef HAPROXY_VERSION
willy tarreauc0d4bbd2006-04-15 21:47:50 +020091#define HAPROXY_VERSION "1.2.12"
willy tarreaubfad5742006-03-23 14:19:11 +010092#endif
93
94#ifndef HAPROXY_DATE
willy tarreauc0d4bbd2006-04-15 21:47:50 +020095#define HAPROXY_DATE "2006/04/15"
willy tarreaubfad5742006-03-23 14:19:11 +010096#endif
willy tarreau0f7af912005-12-17 12:21:26 +010097
98/* this is for libc5 for example */
99#ifndef TCP_NODELAY
100#define TCP_NODELAY 1
101#endif
102
103#ifndef SHUT_RD
104#define SHUT_RD 0
105#endif
106
107#ifndef SHUT_WR
108#define SHUT_WR 1
109#endif
110
willy tarreau0174f312005-12-18 01:02:42 +0100111/*
112 * BUFSIZE defines the size of a read and write buffer. It is the maximum
113 * amount of bytes which can be stored by the proxy for each session. However,
114 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
115 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
116 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
117 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
118 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
119 */
120#ifndef BUFSIZE
121#define BUFSIZE 16384
122#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100123
124// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100125#ifndef MAXREWRITE
126#define MAXREWRITE (BUFSIZE / 2)
127#endif
128
willy tarreau9fe663a2005-12-17 13:02:59 +0100129#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100130#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100131
willy tarreau5cbea6f2005-12-17 12:48:26 +0100132// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100133#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100134
willy tarreaue39cd132005-12-17 13:00:18 +0100135// max # of added headers per request
136#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100137
138// max # of matches per regexp
139#define MAX_MATCH 10
140
willy tarreau0174f312005-12-18 01:02:42 +0100141// cookie delimitor in "prefix" mode. This character is inserted between the
142// persistence cookie and the original value. The '~' is allowed by RFC2965,
143// and should not be too common in server names.
144#ifndef COOKIE_DELIM
145#define COOKIE_DELIM '~'
146#endif
147
willy tarreau0f7af912005-12-17 12:21:26 +0100148#define CONN_RETRIES 3
149
willy tarreau5cbea6f2005-12-17 12:48:26 +0100150#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100151#define DEF_CHKINTR 2000
152#define DEF_FALLTIME 3
153#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100154#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100155
Willy TARREAU13032e72006-03-12 17:31:45 +0100156/* Default connections limit.
157 *
158 * A system limit can be enforced at build time in order to avoid using haproxy
159 * beyond reasonable system limits. For this, just define SYSTEM_MAXCONN to the
160 * absolute limit accepted by the system. If the configuration specifies a
161 * higher value, it will be capped to SYSTEM_MAXCONN and a warning will be
162 * emitted. The only way to override this limit will be to set it via the
163 * command-line '-n' argument.
164 */
165#ifndef SYSTEM_MAXCONN
willy tarreau9fe663a2005-12-17 13:02:59 +0100166#define DEFAULT_MAXCONN 2000
Willy TARREAU13032e72006-03-12 17:31:45 +0100167#else
168#define DEFAULT_MAXCONN SYSTEM_MAXCONN
169#endif
willy tarreau9fe663a2005-12-17 13:02:59 +0100170
willy tarreau0f7af912005-12-17 12:21:26 +0100171/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
172#define INTBITS 5
173
174/* show stats this every millisecond, 0 to disable */
175#ifndef STATTIME
176#define STATTIME 2000
177#endif
178
willy tarreau5cbea6f2005-12-17 12:48:26 +0100179/* this reduces the number of calls to select() by choosing appropriate
180 * sheduler precision in milliseconds. It should be near the minimum
181 * time that is needed by select() to collect all events. All timeouts
182 * are rounded up by adding this value prior to pass it to select().
183 */
184#define SCHEDULER_RESOLUTION 9
185
willy tarreaub952e1d2005-12-18 01:31:20 +0100186#define TIME_ETERNITY -1
187/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100188#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
189#define SETNOW(a) (*a=now)
190
willy tarreau9da061b2005-12-17 12:29:56 +0100191/****** string-specific macros and functions ******/
192/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
193#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
194
195/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
196#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
197
willy tarreau0174f312005-12-18 01:02:42 +0100198/* returns 1 only if only zero or one bit is set in X, which means that X is a
199 * power of 2, and 0 otherwise */
200#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100201/*
202 * copies at most <size-1> chars from <src> to <dst>. Last char is always
203 * set to 0, unless <size> is 0. The number of chars copied is returned
204 * (excluding the terminating zero).
205 * This code has been optimized for size and speed : on x86, it's 45 bytes
206 * long, uses only registers, and consumes only 4 cycles per char.
207 */
willy tarreau750a4722005-12-17 13:21:24 +0100208int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100209 char *orig = dst;
210 if (size) {
211 while (--size && (*dst = *src)) {
212 src++; dst++;
213 }
214 *dst = 0;
215 }
216 return dst - orig;
217}
willy tarreau9da061b2005-12-17 12:29:56 +0100218
willy tarreau4302f492005-12-18 01:00:37 +0100219/*
220 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
221 * dynamically allocated. In the first case, <__pool> is updated to point to
222 * the next element in the list.
223 */
224#define pool_alloc_from(__pool, __len) ({ \
225 void *__p; \
226 if ((__p = (__pool)) == NULL) \
227 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
228 else { \
229 __pool = *(void **)(__pool); \
230 } \
231 __p; \
232})
233
234/*
235 * Puts a memory area back to the corresponding pool.
236 * Items are chained directly through a pointer that
237 * is written in the beginning of the memory area, so
238 * there's no need for any carrier cell. This implies
239 * that each memory area is at least as big as one
240 * pointer.
241 */
242#define pool_free_to(__pool, __ptr) ({ \
243 *(void **)(__ptr) = (void *)(__pool); \
244 __pool = (void *)(__ptr); \
245})
246
247
willy tarreau0f7af912005-12-17 12:21:26 +0100248#define MEM_OPTIM
249#ifdef MEM_OPTIM
250/*
251 * Returns a pointer to type <type> taken from the
252 * pool <pool_type> or dynamically allocated. In the
253 * first case, <pool_type> is updated to point to the
254 * next element in the list.
255 */
256#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100257 void *__p; \
258 if ((__p = pool_##type) == NULL) \
259 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100260 else { \
261 pool_##type = *(void **)pool_##type; \
262 } \
willy tarreau4302f492005-12-18 01:00:37 +0100263 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100264})
265
266/*
267 * Puts a memory area back to the corresponding pool.
268 * Items are chained directly through a pointer that
269 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100270 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100271 * that each memory area is at least as big as one
272 * pointer.
273 */
274#define pool_free(type, ptr) ({ \
275 *(void **)ptr = (void *)pool_##type; \
276 pool_##type = (void *)ptr; \
277})
278
279#else
280#define pool_alloc(type) (calloc(1,sizeof_##type));
281#define pool_free(type, ptr) (free(ptr));
282#endif /* MEM_OPTIM */
283
willy tarreau5cbea6f2005-12-17 12:48:26 +0100284#define sizeof_task sizeof(struct task)
285#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100286#define sizeof_buffer sizeof(struct buffer)
287#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100288#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100289#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100290#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100291#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100292
willy tarreau5cbea6f2005-12-17 12:48:26 +0100293/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100294#define FD_STCLOSE 0
295#define FD_STLISTEN 1
296#define FD_STCONN 2
297#define FD_STREADY 3
298#define FD_STERROR 4
299
willy tarreau5cbea6f2005-12-17 12:48:26 +0100300/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100301#define TASK_IDLE 0
302#define TASK_RUNNING 1
303
willy tarreau5cbea6f2005-12-17 12:48:26 +0100304/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100305#define PR_STNEW 0
306#define PR_STIDLE 1
307#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100308#define PR_STSTOPPED 3
309#define PR_STPAUSED 4
willy tarreau0f7af912005-12-17 12:21:26 +0100310
willy tarreau5cbea6f2005-12-17 12:48:26 +0100311/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100312#define PR_MODE_TCP 0
313#define PR_MODE_HTTP 1
314#define PR_MODE_HEALTH 2
315
willy tarreau1c2ad212005-12-18 01:11:29 +0100316/* possible actions for the *poll() loops */
317#define POLL_LOOP_ACTION_INIT 0
318#define POLL_LOOP_ACTION_RUN 1
319#define POLL_LOOP_ACTION_CLEAN 2
320
willy tarreau64a3cc32005-12-18 01:13:11 +0100321/* poll mechanisms available */
322#define POLL_USE_SELECT (1<<0)
323#define POLL_USE_POLL (1<<1)
324#define POLL_USE_EPOLL (1<<2)
325
willy tarreau5cbea6f2005-12-17 12:48:26 +0100326/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100327#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
328#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
329#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
330#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
331#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
332#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
333#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
334#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau0174f312005-12-18 01:02:42 +0100335#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
336#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
337#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
338#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
339#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
340#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
341#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
342#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
343#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
344#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
345#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100346#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
347#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100348#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100349#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau1a3442d2006-03-24 21:03:20 +0100350#define PR_O_BALANCE_SH 0x00400000 /* balance on source IP hash */
351#define PR_O_BALANCE (PR_O_BALANCE_RR | PR_O_BALANCE_SH)
willy tarreau5cbea6f2005-12-17 12:48:26 +0100352
willy tarreaue39cd132005-12-17 13:00:18 +0100353/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100354#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
355#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
356#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
357#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
358#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
359#define SN_POST 0x00000020 /* the request was an HTTP POST */
willy tarreaub1285d52005-12-18 01:20:14 +0100360#define SN_MONITOR 0x00000040 /* this session comes from a monitoring system */
willy tarreau036e1ce2005-12-17 13:46:33 +0100361
362#define SN_CK_NONE 0x00000000 /* this session had no cookie */
363#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
364#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
365#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
366#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
367#define SN_CK_SHIFT 6 /* bit shift */
368
willy tarreaub1285d52005-12-18 01:20:14 +0100369#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100370#define SN_ERR_CLITO 0x00000100 /* client time-out */
371#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
372#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
373#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
374#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100375#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
376#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100377#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
378#define SN_ERR_SHIFT 8 /* bit shift */
379
380#define SN_FINST_R 0x00001000 /* session ended during client request */
381#define SN_FINST_C 0x00002000 /* session ended during server connect */
382#define SN_FINST_H 0x00003000 /* session ended during server headers */
383#define SN_FINST_D 0x00004000 /* session ended during data phase */
384#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
385#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
386#define SN_FINST_SHIFT 12 /* bit shift */
387
388#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
389#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
390#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
391#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
392#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100393#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100394#define SN_SCK_SHIFT 16 /* bit shift */
395
willy tarreau97f58572005-12-18 00:53:44 +0100396#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
397#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
398#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100399
400/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100401#define CL_STHEADERS 0
402#define CL_STDATA 1
403#define CL_STSHUTR 2
404#define CL_STSHUTW 3
405#define CL_STCLOSE 4
406
willy tarreau5cbea6f2005-12-17 12:48:26 +0100407/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100408#define SV_STIDLE 0
409#define SV_STCONN 1
410#define SV_STHEADERS 2
411#define SV_STDATA 3
412#define SV_STSHUTR 4
413#define SV_STSHUTW 5
414#define SV_STCLOSE 6
415
416/* result of an I/O event */
417#define RES_SILENT 0 /* didn't happen */
418#define RES_DATA 1 /* data were sent or received */
419#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
420#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
421
willy tarreau9fe663a2005-12-17 13:02:59 +0100422/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100423#define MODE_DEBUG 1
424#define MODE_STATS 2
425#define MODE_LOG 4
426#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100427#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100428#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100429#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100430#define MODE_STARTING 128
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100431#define MODE_FOREGROUND 256
willy tarreau5cbea6f2005-12-17 12:48:26 +0100432
433/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100434#define SRV_RUNNING 1 /* the server is UP */
435#define SRV_BACKUP 2 /* this server is a backup server */
436#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100437#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100438#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100439
willy tarreaue39cd132005-12-17 13:00:18 +0100440/* what to do when a header matches a regex */
441#define ACT_ALLOW 0 /* allow the request */
442#define ACT_REPLACE 1 /* replace the matching header */
443#define ACT_REMOVE 2 /* remove the matching header */
444#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100445#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100446
willy tarreau9fe663a2005-12-17 13:02:59 +0100447/* configuration sections */
448#define CFG_NONE 0
449#define CFG_GLOBAL 1
450#define CFG_LISTEN 2
451
willy tarreaua1598082005-12-17 13:08:06 +0100452/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100453#define LW_DATE 1 /* date */
454#define LW_CLIP 2 /* CLient IP */
455#define LW_SVIP 4 /* SerVer IP */
456#define LW_SVID 8 /* server ID */
457#define LW_REQ 16 /* http REQuest */
458#define LW_RESP 32 /* http RESPonse */
459#define LW_PXIP 64 /* proxy IP */
460#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100461#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100462#define LW_COOKIE 512 /* captured cookie */
463#define LW_REQHDR 1024 /* request header(s) */
464#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100465
willy tarreau41310e72006-03-25 18:17:56 +0100466#define ERR_NONE 0 /* no error */
467#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
468#define ERR_FATAL 2 /* fatal error, may be cumulated */
469
willy tarreau0f7af912005-12-17 12:21:26 +0100470/*********************************************************************/
471
472#define LIST_HEAD(a) ((void *)(&(a)))
473
474/*********************************************************************/
475
willy tarreau4302f492005-12-18 01:00:37 +0100476struct cap_hdr {
477 struct cap_hdr *next;
478 char *name; /* header name, case insensitive */
479 int namelen; /* length of the header name, to speed-up lookups */
480 int len; /* capture length, not including terminal zero */
481 int index; /* index in the output array */
482 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
483};
484
willy tarreau0f7af912005-12-17 12:21:26 +0100485struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100486 struct hdr_exp *next;
487 regex_t *preg; /* expression to look for */
488 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
489 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100490};
491
492struct buffer {
493 unsigned int l; /* data length */
494 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100495 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100496 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100497 char data[BUFSIZE];
498};
499
500struct server {
501 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100502 int state; /* server state (SRV_*) */
503 int cklen; /* the len of the cookie, to speed up checks */
504 char *cookie; /* the id set in the cookie */
505 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100506 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100507 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100508 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100509 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100510 int rise, fall; /* time in iterations */
511 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100512 int result; /* 0 = connect OK, -1 = connect KO */
513 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreaue3f023f2006-04-08 21:52:24 +0200514 unsigned char uweight, eweight; /* user-specified weight-1, and effective weight-1 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200515 unsigned int wscore; /* weight score, used during srv map computation */
willy tarreaua647c702006-04-15 22:45:52 +0200516 int cur_sess; /* number of currently active sessions (including syn_sent) */
517 unsigned int cum_sess; /* cumulated number of sessions really sent to this server */
willy tarreau535ae7a2005-12-17 12:58:00 +0100518 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100519};
520
willy tarreau5cbea6f2005-12-17 12:48:26 +0100521/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100522struct task {
523 struct task *next, *prev; /* chaining ... */
524 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100525 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100526 int state; /* task state : IDLE or RUNNING */
527 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100528 int (*process)(struct task *t); /* the function which processes the task */
529 void *context; /* the task's context */
530};
531
532/* WARNING: if new fields are added, they must be initialized in event_accept() */
533struct session {
534 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100535 /* application specific below */
536 struct timeval crexpire; /* expiration date for a client read */
537 struct timeval cwexpire; /* expiration date for a client write */
538 struct timeval srexpire; /* expiration date for a server read */
539 struct timeval swexpire; /* expiration date for a server write */
540 struct timeval cnexpire; /* expiration date for a connect */
541 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
542 struct proxy *proxy; /* the proxy this socket belongs to */
543 int cli_fd; /* the client side fd */
544 int srv_fd; /* the server side fd */
545 int cli_state; /* state of the client side */
546 int srv_state; /* state of the server side */
547 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100548 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100549 struct buffer *req; /* request buffer */
550 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100551 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100552 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100553 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100554 char **req_cap; /* array of captured request headers (may be NULL) */
555 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100556 struct {
557 int logwait; /* log fields waiting to be collected : LW_* */
558 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
559 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
560 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
561 long t_data; /* delay before the first data byte from the server ... */
562 unsigned long t_close; /* total session duration */
563 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100564 char *cli_cookie; /* cookie presented by the client, in capture mode */
565 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100566 int status; /* HTTP status from the server, negative if from proxy */
567 long long bytes; /* number of bytes transferred from the server */
568 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100569 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100570};
571
willy tarreaua41a8b42005-12-17 14:02:24 +0100572struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100573 int fd; /* the listen socket */
574 struct sockaddr_storage addr; /* the address we listen to */
575 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100576};
577
578
willy tarreau0f7af912005-12-17 12:21:26 +0100579struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100580 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100581 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 +0100582 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100583 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200584 struct server *srv; /* known servers */
585 int srv_act, srv_bck; /* # of running servers */
586 int tot_wact, tot_wbck; /* total weights of active and backup servers */
587 struct server **srv_map; /* the server map used to apply weights */
588 int srv_map_sz; /* the size of the effective server map */
589 int srv_rr_idx; /* next server to be elected in round robin mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100590 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100591 int cookie_len; /* strlen(cookie_name), computed only once */
592 char *appsession_name; /* name of the cookie to look for */
593 int appsession_name_len; /* strlen(appsession_name), computed only once */
594 int appsession_len; /* length of the appsession cookie value to be used */
595 int appsession_timeout;
596 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100597 char *capture_name; /* beginning of the name of the cookie to capture */
598 int capture_namelen; /* length of the cookie name to match */
599 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100600 int clitimeout; /* client I/O timeout (in milliseconds) */
601 int srvtimeout; /* server I/O timeout (in milliseconds) */
602 int contimeout; /* connect timeout (in milliseconds) */
603 char *id; /* proxy id */
604 int nbconn; /* # of active sessions */
605 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100606 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100607 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100608 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100609 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100610 struct proxy *next;
611 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100612 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100613 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100614 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100615 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100616 int nb_reqadd, nb_rspadd;
617 struct hdr_exp *req_exp; /* regular expressions for request headers */
618 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100619 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
620 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
621 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
622 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100623 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100624 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100625 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
626 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100627 struct {
628 char *msg400; /* message for error 400 */
629 int len400; /* message length for error 400 */
630 char *msg403; /* message for error 403 */
631 int len403; /* message length for error 403 */
632 char *msg408; /* message for error 408 */
633 int len408; /* message length for error 408 */
634 char *msg500; /* message for error 500 */
635 int len500; /* message length for error 500 */
636 char *msg502; /* message for error 502 */
637 int len502; /* message length for error 502 */
638 char *msg503; /* message for error 503 */
639 int len503; /* message length for error 503 */
640 char *msg504; /* message for error 504 */
641 int len504; /* message length for error 504 */
642 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100643};
644
645/* info about one given fd */
646struct fdtab {
647 int (*read)(int fd); /* read function */
648 int (*write)(int fd); /* write function */
649 struct task *owner; /* the session (or proxy) associated with this fd */
650 int state; /* the state of this fd */
651};
652
653/*********************************************************************/
654
willy tarreaub952e1d2005-12-18 01:31:20 +0100655int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100656int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100657char *cfg_cfgfile = NULL; /* configuration file */
658char *progname = NULL; /* program name */
659int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100660
661/* global options */
662static struct {
663 int uid;
664 int gid;
665 int nbproc;
666 int maxconn;
667 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100668 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100669 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100670 int mode;
671 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100672 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100673 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100674 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100675 struct sockaddr_in logsrv1, logsrv2;
676} global = {
677 logfac1 : -1,
678 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100679 loglev1 : 7, /* max syslog level : debug */
680 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100681 /* others NULL OK */
682};
683
willy tarreau0f7af912005-12-17 12:21:26 +0100684/*********************************************************************/
685
willy tarreau1c2ad212005-12-18 01:11:29 +0100686fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100687 *StaticWriteEvent;
688
willy tarreau64a3cc32005-12-18 01:13:11 +0100689int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100690
willy tarreau0f7af912005-12-17 12:21:26 +0100691void **pool_session = NULL,
692 **pool_buffer = NULL,
693 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100694 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100695 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100696 **pool_capture = NULL,
697 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100698
699struct proxy *proxy = NULL; /* list of all existing proxies */
700struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100701struct task *rq = NULL; /* global run queue */
702struct task wait_queue = { /* global wait queue */
703 prev:LIST_HEAD(wait_queue),
704 next:LIST_HEAD(wait_queue)
705};
willy tarreau0f7af912005-12-17 12:21:26 +0100706
willy tarreau0f7af912005-12-17 12:21:26 +0100707static int totalconn = 0; /* total # of terminated sessions */
708static int actconn = 0; /* # of active sessions */
709static int maxfd = 0; /* # of the highest fd + 1 */
710static int listeners = 0; /* # of listeners */
711static int stopping = 0; /* non zero means stopping in progress */
712static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100713static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100714
willy tarreau53e99702006-03-25 18:53:50 +0100715/* Here we store informations about the pids of the processes we may pause
716 * or kill. We will send them a signal every 10 ms until we can bind to all
717 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100718 */
willy tarreau53e99702006-03-25 18:53:50 +0100719#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100720static int nb_oldpids = 0;
721static int *oldpids = NULL;
722static int oldpids_sig; /* use USR1 or TERM */
723
willy tarreau08dedbe2005-12-18 01:13:48 +0100724#if defined(ENABLE_EPOLL)
725/* FIXME: this is dirty, but at the moment, there's no other solution to remove
726 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
727 * structure with pointers to functions such as init_fd() and close_fd(), plus
728 * a private structure with several pointers to places such as below.
729 */
730
731static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
732#endif
733
willy tarreau0f7af912005-12-17 12:21:26 +0100734static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100735/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100736static char trash[BUFSIZE];
737
willy tarreaudd07e972005-12-18 00:48:48 +0100738const int zero = 0;
739const int one = 1;
740
willy tarreau0f7af912005-12-17 12:21:26 +0100741/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100742 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100743 */
744
745#define MAX_SYSLOG_LEN 1024
746#define NB_LOG_FACILITIES 24
747const char *log_facilities[NB_LOG_FACILITIES] = {
748 "kern", "user", "mail", "daemon",
749 "auth", "syslog", "lpr", "news",
750 "uucp", "cron", "auth2", "ftp",
751 "ntp", "audit", "alert", "cron2",
752 "local0", "local1", "local2", "local3",
753 "local4", "local5", "local6", "local7"
754};
755
756
757#define NB_LOG_LEVELS 8
758const char *log_levels[NB_LOG_LEVELS] = {
759 "emerg", "alert", "crit", "err",
760 "warning", "notice", "info", "debug"
761};
762
763#define SYSLOG_PORT 514
764
765const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
766 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100767
willy tarreaub1285d52005-12-18 01:20:14 +0100768const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100769const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
770const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
771const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
772 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
773 unknown, Set-cookie Rewritten */
774
willy tarreau0f7af912005-12-17 12:21:26 +0100775#define MAX_HOSTNAME_LEN 32
776static char hostname[MAX_HOSTNAME_LEN] = "";
777
willy tarreau8337c6b2005-12-17 13:41:01 +0100778const char *HTTP_302 =
779 "HTTP/1.0 302 Found\r\n"
780 "Cache-Control: no-cache\r\n"
781 "Connection: close\r\n"
782 "Location: "; /* not terminated since it will be concatenated with the URL */
783
willy tarreauc1f47532005-12-18 01:08:26 +0100784/* same as 302 except that the browser MUST retry with the GET method */
785const char *HTTP_303 =
786 "HTTP/1.0 303 See Other\r\n"
787 "Cache-Control: no-cache\r\n"
788 "Connection: close\r\n"
789 "Location: "; /* not terminated since it will be concatenated with the URL */
790
willy tarreaua1598082005-12-17 13:08:06 +0100791const char *HTTP_400 =
792 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100793 "Cache-Control: no-cache\r\n"
794 "Connection: close\r\n"
795 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100796 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100797
willy tarreaua1598082005-12-17 13:08:06 +0100798const char *HTTP_403 =
799 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100800 "Cache-Control: no-cache\r\n"
801 "Connection: close\r\n"
802 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100803 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
804
willy tarreau8337c6b2005-12-17 13:41:01 +0100805const char *HTTP_408 =
806 "HTTP/1.0 408 Request Time-out\r\n"
807 "Cache-Control: no-cache\r\n"
808 "Connection: close\r\n"
809 "\r\n"
810 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
811
willy tarreau750a4722005-12-17 13:21:24 +0100812const char *HTTP_500 =
813 "HTTP/1.0 500 Server Error\r\n"
814 "Cache-Control: no-cache\r\n"
815 "Connection: close\r\n"
816 "\r\n"
817 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100818
819const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100820 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100821 "Cache-Control: no-cache\r\n"
822 "Connection: close\r\n"
823 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100824 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
825
826const char *HTTP_503 =
827 "HTTP/1.0 503 Service Unavailable\r\n"
828 "Cache-Control: no-cache\r\n"
829 "Connection: close\r\n"
830 "\r\n"
831 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
832
833const char *HTTP_504 =
834 "HTTP/1.0 504 Gateway Time-out\r\n"
835 "Cache-Control: no-cache\r\n"
836 "Connection: close\r\n"
837 "\r\n"
838 "<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 +0100839
willy tarreau0f7af912005-12-17 12:21:26 +0100840/*********************************************************************/
841/* statistics ******************************************************/
842/*********************************************************************/
843
willy tarreau750a4722005-12-17 13:21:24 +0100844#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100845static int stats_tsk_lsrch, stats_tsk_rsrch,
846 stats_tsk_good, stats_tsk_right, stats_tsk_left,
847 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100848#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100849
850
851/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100852/* debugging *******************************************************/
853/*********************************************************************/
854#ifdef DEBUG_FULL
855static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
856static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
857#endif
858
859/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100860/* function prototypes *********************************************/
861/*********************************************************************/
862
863int event_accept(int fd);
864int event_cli_read(int fd);
865int event_cli_write(int fd);
866int event_srv_read(int fd);
867int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100868int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100869
willy tarreau12350152005-12-18 01:03:27 +0100870static int appsession_task_init(void);
871static int appsession_init(void);
872static int appsession_refresh(struct task *t);
873
willy tarreau0f7af912005-12-17 12:21:26 +0100874/*********************************************************************/
875/* general purpose functions ***************************************/
876/*********************************************************************/
877
878void display_version() {
879 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100880 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100881}
882
883/*
884 * This function prints the command line usage and exits
885 */
886void usage(char *name) {
887 display_version();
888 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100889 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100890#if STATTIME > 0
891 "sl"
892#endif
willy tarreau746e26b2006-03-25 11:14:35 +0100893 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
894 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100895 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100896 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +0100897 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100898#if STATTIME > 0
899 " -s enables statistics output\n"
900 " -l enables long statistics format\n"
901#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100902 " -D goes daemon ; implies -q\n"
903 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100904 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100905 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +0100906 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100907 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100908 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100909#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100910 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100911#endif
912#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100913 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100914#endif
willy tarreau53e99702006-03-25 18:53:50 +0100915 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100916 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100917 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100918 exit(1);
919}
920
921
922/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100923 * Displays the message on stderr with the date and pid. Overrides the quiet
924 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100925 */
926void Alert(char *fmt, ...) {
927 va_list argp;
928 struct timeval tv;
929 struct tm *tm;
930
willy tarreaud0fb4652005-12-18 01:32:04 +0100931 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100932 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100933
willy tarreau5cbea6f2005-12-17 12:48:26 +0100934 gettimeofday(&tv, NULL);
935 tm=localtime(&tv.tv_sec);
936 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100937 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100938 vfprintf(stderr, fmt, argp);
939 fflush(stderr);
940 va_end(argp);
941 }
willy tarreau0f7af912005-12-17 12:21:26 +0100942}
943
944
945/*
946 * Displays the message on stderr with the date and pid.
947 */
948void Warning(char *fmt, ...) {
949 va_list argp;
950 struct timeval tv;
951 struct tm *tm;
952
willy tarreau982249e2005-12-18 00:57:06 +0100953 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100954 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100955
willy tarreau5cbea6f2005-12-17 12:48:26 +0100956 gettimeofday(&tv, NULL);
957 tm=localtime(&tv.tv_sec);
958 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100959 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100960 vfprintf(stderr, fmt, argp);
961 fflush(stderr);
962 va_end(argp);
963 }
964}
965
966/*
967 * Displays the message on <out> only if quiet mode is not set.
968 */
969void qfprintf(FILE *out, char *fmt, ...) {
970 va_list argp;
971
willy tarreau982249e2005-12-18 00:57:06 +0100972 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100973 va_start(argp, fmt);
974 vfprintf(out, fmt, argp);
975 fflush(out);
976 va_end(argp);
977 }
willy tarreau0f7af912005-12-17 12:21:26 +0100978}
979
980
981/*
982 * converts <str> to a struct sockaddr_in* which is locally allocated.
983 * The format is "addr:port", where "addr" can be empty or "*" to indicate
984 * INADDR_ANY.
985 */
986struct sockaddr_in *str2sa(char *str) {
987 static struct sockaddr_in sa;
988 char *c;
989 int port;
990
willy tarreaua1598082005-12-17 13:08:06 +0100991 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100992 str=strdup(str);
993
994 if ((c=strrchr(str,':')) != NULL) {
995 *c++=0;
996 port=atol(c);
997 }
998 else
999 port=0;
1000
1001 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1002 sa.sin_addr.s_addr = INADDR_ANY;
1003 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01001004 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001005 struct hostent *he;
1006
1007 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001008 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001009 }
1010 else
1011 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1012 }
1013 sa.sin_port=htons(port);
1014 sa.sin_family=AF_INET;
1015
1016 free(str);
1017 return &sa;
1018}
1019
willy tarreaub1285d52005-12-18 01:20:14 +01001020/*
1021 * converts <str> to a two struct in_addr* which are locally allocated.
1022 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1023 * is optionnal and either in the dotted or CIDR notation.
1024 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1025 */
1026int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1027 char *c;
1028 unsigned long len;
1029
1030 memset(mask, 0, sizeof(*mask));
1031 memset(addr, 0, sizeof(*addr));
1032 str=strdup(str);
1033
1034 if ((c = strrchr(str, '/')) != NULL) {
1035 *c++ = 0;
1036 /* c points to the mask */
1037 if (strchr(c, '.') != NULL) { /* dotted notation */
1038 if (!inet_pton(AF_INET, c, mask))
1039 return 0;
1040 }
1041 else { /* mask length */
1042 char *err;
1043 len = strtol(c, &err, 10);
1044 if (!*c || (err && *err) || (unsigned)len > 32)
1045 return 0;
1046 if (len)
1047 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1048 else
1049 mask->s_addr = 0;
1050 }
1051 }
1052 else {
1053 mask->s_addr = 0xFFFFFFFF;
1054 }
1055 if (!inet_pton(AF_INET, str, addr)) {
1056 struct hostent *he;
1057
1058 if ((he = gethostbyname(str)) == NULL) {
1059 return 0;
1060 }
1061 else
1062 *addr = *(struct in_addr *) *(he->h_addr_list);
1063 }
1064 free(str);
1065 return 1;
1066}
1067
willy tarreau9fe663a2005-12-17 13:02:59 +01001068
1069/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001070 * converts <str> to a list of listeners which are dynamically allocated.
1071 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1072 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1073 * - <port> is a numerical port from 1 to 65535 ;
1074 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1075 * This can be repeated as many times as necessary, separated by a coma.
1076 * The <tail> argument is a pointer to a current list which should be appended
1077 * to the tail of the new list. The pointer to the new list is returned.
1078 */
1079struct listener *str2listener(char *str, struct listener *tail) {
1080 struct listener *l;
1081 char *c, *next, *range, *dupstr;
1082 int port, end;
1083
1084 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001085
willy tarreaua41a8b42005-12-17 14:02:24 +01001086 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001087 struct sockaddr_storage ss;
1088
willy tarreaua41a8b42005-12-17 14:02:24 +01001089 str = next;
1090 /* 1) look for the end of the first address */
1091 if ((next = strrchr(str, ',')) != NULL) {
1092 *next++ = 0;
1093 }
1094
willy tarreau8a86dbf2005-12-18 00:45:59 +01001095 /* 2) look for the addr/port delimiter, it's the last colon. */
1096 if ((range = strrchr(str, ':')) == NULL) {
1097 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001098 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001099 }
1100
1101 *range++ = 0;
1102
1103 if (strrchr(str, ':') != NULL) {
1104 /* IPv6 address contains ':' */
1105 memset(&ss, 0, sizeof(ss));
1106 ss.ss_family = AF_INET6;
1107
1108 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1109 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001110 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001111 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001112 }
1113 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001114 memset(&ss, 0, sizeof(ss));
1115 ss.ss_family = AF_INET;
1116
1117 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1118 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1119 }
1120 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1121 struct hostent *he;
1122
1123 if ((he = gethostbyname(str)) == NULL) {
1124 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001125 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001126 }
1127 else
1128 ((struct sockaddr_in *)&ss)->sin_addr =
1129 *(struct in_addr *) *(he->h_addr_list);
1130 }
1131 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001132
1133 /* 3) look for the port-end delimiter */
1134 if ((c = strchr(range, '-')) != NULL) {
1135 *c++ = 0;
1136 end = atol(c);
1137 }
1138 else {
1139 end = atol(range);
1140 }
1141
willy tarreaud0fb4652005-12-18 01:32:04 +01001142 port = atol(range);
1143
1144 if (port < 1 || port > 65535) {
1145 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1146 goto fail;
1147 }
1148
1149 if (end < 1 || end > 65535) {
1150 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1151 goto fail;
1152 }
1153
1154 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001155 l = (struct listener *)calloc(1, sizeof(struct listener));
1156 l->next = tail;
1157 tail = l;
1158
willy tarreau41310e72006-03-25 18:17:56 +01001159 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001160 l->addr = ss;
1161 if (ss.ss_family == AF_INET6)
1162 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1163 else
1164 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1165
willy tarreaua41a8b42005-12-17 14:02:24 +01001166 } /* end for(port) */
1167 } /* end while(next) */
1168 free(dupstr);
1169 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001170 fail:
1171 free(dupstr);
1172 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001173}
1174
willy tarreau4302f492005-12-18 01:00:37 +01001175
1176#define FD_SETS_ARE_BITFIELDS
1177#ifdef FD_SETS_ARE_BITFIELDS
1178/*
1179 * This map is used with all the FD_* macros to check whether a particular bit
1180 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1181 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1182 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1183 * exclusively to the macros.
1184 */
1185fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1186fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1187
1188#else
1189#error "Check if your OS uses bitfields for fd_sets"
1190#endif
1191
1192/* will try to encode the string <string> replacing all characters tagged in
1193 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1194 * prefixed by <escape>, and will store the result between <start> (included
1195 *) and <stop> (excluded), and will always terminate the string with a '\0'
1196 * before <stop>. The position of the '\0' is returned if the conversion
1197 * completes. If bytes are missing between <start> and <stop>, then the
1198 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1199 * cannot even be stored so we return <start> without writing the 0.
1200 * The input string must also be zero-terminated.
1201 */
1202char hextab[16] = "0123456789ABCDEF";
1203char *encode_string(char *start, char *stop,
1204 const char escape, const fd_set *map,
1205 const char *string)
1206{
1207 if (start < stop) {
1208 stop--; /* reserve one byte for the final '\0' */
1209 while (start < stop && *string != 0) {
1210 if (!FD_ISSET((unsigned char)(*string), map))
1211 *start++ = *string;
1212 else {
1213 if (start + 3 >= stop)
1214 break;
1215 *start++ = escape;
1216 *start++ = hextab[(*string >> 4) & 15];
1217 *start++ = hextab[*string & 15];
1218 }
1219 string++;
1220 }
1221 *start = '\0';
1222 }
1223 return start;
1224}
willy tarreaua41a8b42005-12-17 14:02:24 +01001225
1226/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001227 * This function sends a syslog message to both log servers of a proxy,
1228 * or to global log servers if the proxy is NULL.
1229 * It also tries not to waste too much time computing the message header.
1230 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001231 */
1232void send_log(struct proxy *p, int level, char *message, ...) {
1233 static int logfd = -1; /* syslog UDP socket */
1234 static long tvsec = -1; /* to force the string to be initialized */
1235 struct timeval tv;
1236 va_list argp;
1237 static char logmsg[MAX_SYSLOG_LEN];
1238 static char *dataptr = NULL;
1239 int fac_level;
1240 int hdr_len, data_len;
1241 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001242 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001243 int nbloggers = 0;
1244 char *log_ptr;
1245
1246 if (logfd < 0) {
1247 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1248 return;
1249 }
1250
1251 if (level < 0 || progname == NULL || message == NULL)
1252 return;
1253
1254 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001255 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001256 /* this string is rebuild only once a second */
1257 struct tm *tm = localtime(&tv.tv_sec);
1258 tvsec = tv.tv_sec;
1259
willy tarreauc29948c2005-12-17 13:10:27 +01001260 hdr_len = snprintf(logmsg, sizeof(logmsg),
1261 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1262 monthname[tm->tm_mon],
1263 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1264 progname, pid);
1265 /* WARNING: depending upon implementations, snprintf may return
1266 * either -1 or the number of bytes that would be needed to store
1267 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001268 */
willy tarreauc29948c2005-12-17 13:10:27 +01001269 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1270 hdr_len = sizeof(logmsg);
1271
1272 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001273 }
1274
1275 va_start(argp, message);
1276 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001277 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1278 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001279 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001280 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001281
1282 if (p == NULL) {
1283 if (global.logfac1 >= 0) {
1284 sa[nbloggers] = &global.logsrv1;
1285 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001286 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001287 nbloggers++;
1288 }
1289 if (global.logfac2 >= 0) {
1290 sa[nbloggers] = &global.logsrv2;
1291 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001292 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001293 nbloggers++;
1294 }
1295 } else {
1296 if (p->logfac1 >= 0) {
1297 sa[nbloggers] = &p->logsrv1;
1298 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001299 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001300 nbloggers++;
1301 }
1302 if (p->logfac2 >= 0) {
1303 sa[nbloggers] = &p->logsrv2;
1304 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001305 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001306 nbloggers++;
1307 }
1308 }
1309
1310 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001311 /* we can filter the level of the messages that are sent to each logger */
1312 if (level > loglevel[nbloggers])
1313 continue;
1314
willy tarreauc29948c2005-12-17 13:10:27 +01001315 /* For each target, we may have a different facility.
1316 * We can also have a different log level for each message.
1317 * This induces variations in the message header length.
1318 * Since we don't want to recompute it each time, nor copy it every
1319 * time, we only change the facility in the pre-computed header,
1320 * and we change the pointer to the header accordingly.
1321 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001322 fac_level = (facilities[nbloggers] << 3) + level;
1323 log_ptr = logmsg + 3; /* last digit of the log level */
1324 do {
1325 *log_ptr = '0' + fac_level % 10;
1326 fac_level /= 10;
1327 log_ptr--;
1328 } while (fac_level && log_ptr > logmsg);
1329 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001330
willy tarreauc29948c2005-12-17 13:10:27 +01001331 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001332
1333#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001334 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001335 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1336#else
willy tarreauc29948c2005-12-17 13:10:27 +01001337 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001338 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1339#endif
1340 }
willy tarreau0f7af912005-12-17 12:21:26 +01001341}
1342
1343
1344/* sets <tv> to the current time */
1345static inline struct timeval *tv_now(struct timeval *tv) {
1346 if (tv)
1347 gettimeofday(tv, NULL);
1348 return tv;
1349}
1350
1351/*
1352 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1353 */
1354static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1355 if (!tv || !from)
1356 return NULL;
1357 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1358 tv->tv_sec = from->tv_sec + (ms/1000);
1359 while (tv->tv_usec >= 1000000) {
1360 tv->tv_usec -= 1000000;
1361 tv->tv_sec++;
1362 }
1363 return tv;
1364}
1365
1366/*
1367 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001368 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001369 */
1370static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001371 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001372 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001373 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001374 return 1;
1375 else if (tv1->tv_usec < tv2->tv_usec)
1376 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001377 else if (tv1->tv_usec > tv2->tv_usec)
1378 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001379 else
1380 return 0;
1381}
1382
1383/*
1384 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001385 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001386 */
1387unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1388 int cmp;
1389 unsigned long ret;
1390
1391
willy tarreauef900ab2005-12-17 12:52:52 +01001392 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001393 if (!cmp)
1394 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001395 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001396 struct timeval *tmp = tv1;
1397 tv1 = tv2;
1398 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001399 }
willy tarreauef900ab2005-12-17 12:52:52 +01001400 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001401 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001402 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001403 else
willy tarreauef900ab2005-12-17 12:52:52 +01001404 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001405 return (unsigned long) ret;
1406}
1407
1408/*
willy tarreau750a4722005-12-17 13:21:24 +01001409 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001410 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001411 */
1412static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1413 unsigned long ret;
1414
willy tarreau6e682ce2005-12-17 13:26:49 +01001415 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1416 if (tv2->tv_usec > tv1->tv_usec)
1417 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001418 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001419 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001420 return (unsigned long) ret;
1421}
1422
1423/*
willy tarreau0f7af912005-12-17 12:21:26 +01001424 * 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 +01001425 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001426 */
1427static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001428 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001429 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001430 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001431 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001432 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001433 else
1434 return 0;
1435 }
willy tarreau0f7af912005-12-17 12:21:26 +01001436 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001437 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001438 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001439 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001440 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001441 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001442 else
1443 return 0;
1444}
1445
1446/*
1447 * returns the remaining time between tv1=now and event=tv2
1448 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001449 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001450 */
1451static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1452 unsigned long ret;
1453
willy tarreau0f7af912005-12-17 12:21:26 +01001454 if (tv_cmp_ms(tv1, tv2) >= 0)
1455 return 0; /* event elapsed */
1456
willy tarreauef900ab2005-12-17 12:52:52 +01001457 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001458 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001459 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001460 else
willy tarreauef900ab2005-12-17 12:52:52 +01001461 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001462 return (unsigned long) ret;
1463}
1464
1465
1466/*
1467 * zeroes a struct timeval
1468 */
1469
1470static inline struct timeval *tv_eternity(struct timeval *tv) {
1471 tv->tv_sec = tv->tv_usec = 0;
1472 return tv;
1473}
1474
1475/*
1476 * returns 1 if tv is null, else 0
1477 */
1478static inline int tv_iseternity(struct timeval *tv) {
1479 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1480 return 1;
1481 else
1482 return 0;
1483}
1484
1485/*
1486 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1487 * considering that 0 is the eternity.
1488 */
1489static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1490 if (tv_iseternity(tv1))
1491 if (tv_iseternity(tv2))
1492 return 0; /* same */
1493 else
1494 return 1; /* tv1 later than tv2 */
1495 else if (tv_iseternity(tv2))
1496 return -1; /* tv2 later than tv1 */
1497
1498 if (tv1->tv_sec > tv2->tv_sec)
1499 return 1;
1500 else if (tv1->tv_sec < tv2->tv_sec)
1501 return -1;
1502 else if (tv1->tv_usec > tv2->tv_usec)
1503 return 1;
1504 else if (tv1->tv_usec < tv2->tv_usec)
1505 return -1;
1506 else
1507 return 0;
1508}
1509
1510/*
1511 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1512 * considering that 0 is the eternity.
1513 */
1514static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1515 if (tv_iseternity(tv1))
1516 if (tv_iseternity(tv2))
1517 return 0; /* same */
1518 else
1519 return 1; /* tv1 later than tv2 */
1520 else if (tv_iseternity(tv2))
1521 return -1; /* tv2 later than tv1 */
1522
willy tarreauefae1842005-12-17 12:51:03 +01001523 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001524 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001525 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001526 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001527 return -1;
1528 else
1529 return 0;
1530 }
1531 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001532 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001533 return 1;
1534 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001535 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001536 return -1;
1537 else
1538 return 0;
1539}
1540
1541/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001542 * returns the remaining time between tv1=now and event=tv2
1543 * if tv2 is passed, 0 is returned.
1544 * Returns TIME_ETERNITY if tv2 is eternity.
1545 */
1546static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1547 unsigned long ret;
1548
1549 if (tv_iseternity(tv2))
1550 return TIME_ETERNITY;
1551
1552 if (tv_cmp_ms(tv1, tv2) >= 0)
1553 return 0; /* event elapsed */
1554
1555 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1556 if (tv2->tv_usec > tv1->tv_usec)
1557 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1558 else
1559 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1560 return (unsigned long) ret;
1561}
1562
1563/*
willy tarreau0f7af912005-12-17 12:21:26 +01001564 * returns the first event between tv1 and tv2 into tvmin.
1565 * a zero tv is ignored. tvmin is returned.
1566 */
1567static inline struct timeval *tv_min(struct timeval *tvmin,
1568 struct timeval *tv1, struct timeval *tv2) {
1569
1570 if (tv_cmp2(tv1, tv2) <= 0)
1571 *tvmin = *tv1;
1572 else
1573 *tvmin = *tv2;
1574
1575 return tvmin;
1576}
1577
1578
1579
1580/***********************************************************/
1581/* fd management ***************************************/
1582/***********************************************************/
1583
1584
1585
willy tarreau5cbea6f2005-12-17 12:48:26 +01001586/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1587 * The file descriptor is also closed.
1588 */
willy tarreau0f7af912005-12-17 12:21:26 +01001589static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001590 FD_CLR(fd, StaticReadEvent);
1591 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001592#if defined(ENABLE_EPOLL)
1593 if (PrevReadEvent) {
1594 FD_CLR(fd, PrevReadEvent);
1595 FD_CLR(fd, PrevWriteEvent);
1596 }
1597#endif
1598
willy tarreau5cbea6f2005-12-17 12:48:26 +01001599 close(fd);
1600 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001601
1602 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1603 maxfd--;
1604}
1605
1606/* recomputes the maxfd limit from the fd */
1607static inline void fd_insert(int fd) {
1608 if (fd+1 > maxfd)
1609 maxfd = fd+1;
1610}
1611
1612/*************************************************************/
1613/* task management ***************************************/
1614/*************************************************************/
1615
willy tarreau5cbea6f2005-12-17 12:48:26 +01001616/* puts the task <t> in run queue <q>, and returns <t> */
1617static inline struct task *task_wakeup(struct task **q, struct task *t) {
1618 if (t->state == TASK_RUNNING)
1619 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001620 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001621 t->rqnext = *q;
1622 t->state = TASK_RUNNING;
1623 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001624 }
1625}
1626
willy tarreau5cbea6f2005-12-17 12:48:26 +01001627/* removes the task <t> from the queue <q>
1628 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001629 * set the run queue to point to the next one, and return it
1630 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001631static inline struct task *task_sleep(struct task **q, struct task *t) {
1632 if (t->state == TASK_RUNNING) {
1633 *q = t->rqnext;
1634 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001635 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001636 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001637}
1638
1639/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001640 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001641 * from the run queue. A pointer to the task itself is returned.
1642 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001643static inline struct task *task_delete(struct task *t) {
1644 t->prev->next = t->next;
1645 t->next->prev = t->prev;
1646 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001647}
1648
1649/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001650 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001651 */
1652static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001653 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001654}
1655
willy tarreau5cbea6f2005-12-17 12:48:26 +01001656/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001657 * may be only moved or left where it was, depending on its timing requirements.
1658 * <task> is returned.
1659 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001660struct task *task_queue(struct task *task) {
1661 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001662 struct task *start_from;
1663
1664 /* first, test if the task was already in a list */
1665 if (task->prev == NULL) {
1666 // start_from = list;
1667 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001668#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001669 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001670#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001671 /* insert the unlinked <task> into the list, searching back from the last entry */
1672 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1673 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001674#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001675 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001676#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001677 }
1678
1679 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1680 // start_from = start_from->next;
1681 // stats_tsk_nsrch++;
1682 // }
1683 }
1684 else if (task->prev == list ||
1685 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1686 start_from = task->next;
1687 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001688#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001689 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001690#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001691 return task; /* it's already in the right place */
1692 }
1693
willy tarreau750a4722005-12-17 13:21:24 +01001694#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001695 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001696#endif
1697
1698 /* if the task is not at the right place, there's little chance that
1699 * it has only shifted a bit, and it will nearly always be queued
1700 * at the end of the list because of constant timeouts
1701 * (observed in real case).
1702 */
1703#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1704 start_from = list->prev; /* assume we'll queue to the end of the list */
1705 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1706 start_from = start_from->prev;
1707#if STATTIME > 0
1708 stats_tsk_lsrch++;
1709#endif
1710 }
1711#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001712 /* insert the unlinked <task> into the list, searching after position <start_from> */
1713 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1714 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001715#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001716 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001717#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001718 }
willy tarreau750a4722005-12-17 13:21:24 +01001719#endif /* WE_REALLY_... */
1720
willy tarreau0f7af912005-12-17 12:21:26 +01001721 /* we need to unlink it now */
1722 task_delete(task);
1723 }
1724 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001725#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001726 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001727#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001728#ifdef LEFT_TO_TOP /* not very good */
1729 start_from = list;
1730 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1731 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001732#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001733 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001734#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001735 }
1736#else
1737 start_from = task->prev->prev; /* valid because of the previous test above */
1738 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1739 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001740#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001741 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001742#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001743 }
1744#endif
1745 /* we need to unlink it now */
1746 task_delete(task);
1747 }
1748 task->prev = start_from;
1749 task->next = start_from->next;
1750 task->next->prev = task;
1751 start_from->next = task;
1752 return task;
1753}
1754
1755
1756/*********************************************************************/
1757/* more specific functions ***************************************/
1758/*********************************************************************/
1759
1760/* some prototypes */
1761static int maintain_proxies(void);
1762
willy tarreaub952e1d2005-12-18 01:31:20 +01001763/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001764 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1765 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001766static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001767#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001768 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1769#else
willy tarreaua1598082005-12-17 13:08:06 +01001770#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001771 return getsockname(fd, (struct sockaddr *)sa, salen);
1772#else
1773 return -1;
1774#endif
1775#endif
1776}
1777
1778/*
1779 * frees the context associated to a session. It must have been removed first.
1780 */
1781static inline void session_free(struct session *s) {
1782 if (s->req)
1783 pool_free(buffer, s->req);
1784 if (s->rep)
1785 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001786
1787 if (s->rsp_cap != NULL) {
1788 struct cap_hdr *h;
1789 for (h = s->proxy->rsp_cap; h; h = h->next) {
1790 if (s->rsp_cap[h->index] != NULL)
1791 pool_free_to(h->pool, s->rsp_cap[h->index]);
1792 }
1793 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1794 }
1795 if (s->req_cap != NULL) {
1796 struct cap_hdr *h;
1797 for (h = s->proxy->req_cap; h; h = h->next) {
1798 if (s->req_cap[h->index] != NULL)
1799 pool_free_to(h->pool, s->req_cap[h->index]);
1800 }
1801 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1802 }
1803
willy tarreaua1598082005-12-17 13:08:06 +01001804 if (s->logs.uri)
1805 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001806 if (s->logs.cli_cookie)
1807 pool_free(capture, s->logs.cli_cookie);
1808 if (s->logs.srv_cookie)
1809 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001810
willy tarreau5cbea6f2005-12-17 12:48:26 +01001811 pool_free(session, s);
1812}
1813
willy tarreau0f7af912005-12-17 12:21:26 +01001814
1815/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01001816 * This function recounts the number of usable active and backup servers for
1817 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001818 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01001819 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001820static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001821 struct server *srv;
1822
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001823 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001824 for (srv = px->srv; srv != NULL; srv = srv->next) {
1825 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001826 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001827 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001828 px->tot_wbck += srv->eweight + 1;
1829 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001830 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001831 px->tot_wact += srv->eweight + 1;
1832 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01001833 }
1834 }
1835}
1836
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001837/* This function recomputes the server map for proxy px. It
1838 * relies on px->tot_wact and px->tot_wbck, so it must be
1839 * called after recount_servers(). It also expects px->srv_map
1840 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01001841 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001842static void recalc_server_map(struct proxy *px) {
1843 int o, tot, flag;
1844 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01001845
willy tarreau4c8c2b52006-03-24 19:36:41 +01001846 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001847 flag = SRV_RUNNING;
1848 tot = px->tot_wact;
1849 } else if (px->srv_bck) {
1850 flag = SRV_RUNNING | SRV_BACKUP;
1851 if (px->options & PR_O_USE_ALL_BK)
1852 tot = px->tot_wbck;
1853 else
1854 tot = 1; /* the first server is enough */
1855 } else {
1856 px->srv_map_sz = 0;
1857 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001858 }
Willy TARREAU3481c462006-03-01 22:37:57 +01001859
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001860 /* this algorithm gives priority to the first server, which means that
1861 * it will respect the declaration order for equivalent weights, and
1862 * that whatever the weights, the first server called will always be
1863 * the first declard. This is an important asumption for the backup
1864 * case, where we want the first server only.
1865 */
1866 for (cur = px->srv; cur; cur = cur->next)
1867 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001868
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001869 for (o = 0; o < tot; o++) {
1870 int max = 0;
1871 best = NULL;
1872 for (cur = px->srv; cur; cur = cur->next) {
1873 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
1874 int v;
1875
1876 /* If we are forced to return only one server, we don't want to
1877 * go further, because we would return the wrong one due to
1878 * divide overflow.
1879 */
1880 if (tot == 1) {
1881 best = cur;
1882 break;
1883 }
1884
1885 cur->wscore += cur->eweight + 1;
1886 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
1887 if (best == NULL || v > max) {
1888 max = v;
1889 best = cur;
1890 }
1891 }
1892 }
1893 px->srv_map[o] = best;
1894 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001895 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001896 px->srv_map_sz = tot;
1897}
Willy TARREAU3481c462006-03-01 22:37:57 +01001898
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001899/*
1900 * This function tries to find a running server for the proxy <px> following
1901 * the round-robin method. Depending on the number of active/backup servers,
1902 * it will either look for active servers, or for backup servers.
1903 * If any server is found, it will be returned and px->srv_rr_idx will be updated
1904 * to point to the next server. If no valid server is found, NULL is returned.
1905 */
1906static inline struct server *get_server_rr(struct proxy *px) {
1907 if (px->srv_map_sz == 0)
1908 return NULL;
1909
1910 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
1911 px->srv_rr_idx = 0;
1912 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01001913}
1914
willy tarreau62084d42006-03-24 18:57:41 +01001915
1916/*
willy tarreau1a3442d2006-03-24 21:03:20 +01001917 * This function tries to find a running server for the proxy <px> following
1918 * the source hash method. Depending on the number of active/backup servers,
1919 * it will either look for active servers, or for backup servers.
1920 * If any server is found, it will be returned. If no valid server is found,
1921 * NULL is returned.
1922 */
1923static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001924 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01001925
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001926 if (px->srv_map_sz == 0)
1927 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01001928
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001929 l = h = 0;
1930 if (px->srv_act > 1) {
1931 while ((l + sizeof (int)) <= len) {
1932 h ^= ntohl(*(unsigned int *)(&addr[l]));
1933 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01001934 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001935 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01001936 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001937 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01001938}
1939
1940
1941/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001942 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01001943 * is set, or to the dispatch server if (s->direct) is 0.
1944 * It can return one of :
1945 * - SN_ERR_NONE if everything's OK
1946 * - SN_ERR_SRVTO if there are no more servers
1947 * - SN_ERR_SRVCL if the connection was refused by the server
1948 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1949 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1950 * - SN_ERR_INTERNAL for any other purely internal errors
1951 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01001952 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001953int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001954 int fd;
1955
willy tarreau12350152005-12-18 01:03:27 +01001956#ifdef DEBUG_FULL
1957 fprintf(stderr,"connect_server : s=%p\n",s);
1958#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001959
willy tarreaue39cd132005-12-17 13:00:18 +01001960 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001961 s->srv_addr = s->srv->addr;
1962 }
1963 else if (s->proxy->options & PR_O_BALANCE) {
willy tarreau1a3442d2006-03-24 21:03:20 +01001964 /* Ensure that srv will not be NULL */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001965 if (!s->proxy->srv_act && !s->proxy->srv_bck)
1966 return SN_ERR_SRVTO;
1967
willy tarreau5cbea6f2005-12-17 12:48:26 +01001968 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001969 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001970
willy tarreau4c8c2b52006-03-24 19:36:41 +01001971 srv = get_server_rr(s->proxy);
willy tarreau8337c6b2005-12-17 13:41:01 +01001972 s->srv_addr = srv->addr;
1973 s->srv = srv;
willy tarreau0f7af912005-12-17 12:21:26 +01001974 }
willy tarreau1a3442d2006-03-24 21:03:20 +01001975 else if (s->proxy->options & PR_O_BALANCE_SH) {
1976 struct server *srv;
1977 int len;
1978
1979 if (s->cli_addr.ss_family == AF_INET)
1980 len = 4;
1981 else if (s->cli_addr.ss_family == AF_INET6)
1982 len = 16;
1983 else /* unknown IP family */
1984 return SN_ERR_INTERNAL;
1985
1986 srv = get_server_sh(s->proxy,
1987 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
1988 len);
1989 s->srv_addr = srv->addr;
1990 s->srv = srv;
1991 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001992 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01001993 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001994 }
willy tarreaua1598082005-12-17 13:08:06 +01001995 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001996 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001997 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001998 }
1999 else if (s->proxy->options & PR_O_TRANSP) {
2000 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002001 socklen_t salen = sizeof(s->srv_addr);
2002
willy tarreau5cbea6f2005-12-17 12:48:26 +01002003 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2004 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002005 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002006 }
2007 }
willy tarreau0f7af912005-12-17 12:21:26 +01002008
willy tarreaua41a8b42005-12-17 14:02:24 +01002009 /* if this server remaps proxied ports, we'll use
2010 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01002011 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01002012 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002013 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01002014
willy tarreaub952e1d2005-12-18 01:31:20 +01002015 if (!(s->proxy->options & PR_O_TRANSP) ||
2016 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01002017 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2018 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
2019 }
2020
willy tarreau0f7af912005-12-17 12:21:26 +01002021 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002022 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002023
2024 if (errno == ENFILE)
2025 send_log(s->proxy, LOG_EMERG,
2026 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2027 s->proxy->id, maxfd);
2028 else if (errno == EMFILE)
2029 send_log(s->proxy, LOG_EMERG,
2030 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2031 s->proxy->id, maxfd);
2032 else if (errno == ENOBUFS || errno == ENOMEM)
2033 send_log(s->proxy, LOG_EMERG,
2034 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2035 s->proxy->id, maxfd);
2036 /* this is a resource error */
2037 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002038 }
2039
willy tarreau9fe663a2005-12-17 13:02:59 +01002040 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002041 /* do not log anything there, it's a normal condition when this option
2042 * is used to serialize connections to a server !
2043 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002044 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2045 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002046 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002047 }
2048
willy tarreau0f7af912005-12-17 12:21:26 +01002049 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2050 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002051 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002052 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002053 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002054 }
2055
willy tarreaub952e1d2005-12-18 01:31:20 +01002056 if (s->proxy->options & PR_O_TCP_SRV_KA)
2057 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2058
willy tarreau0174f312005-12-18 01:02:42 +01002059 /* allow specific binding :
2060 * - server-specific at first
2061 * - proxy-specific next
2062 */
2063 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2064 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2065 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2066 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2067 s->proxy->id, s->srv->id);
2068 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002069 send_log(s->proxy, LOG_EMERG,
2070 "Cannot bind to source address before connect() for server %s/%s.\n",
2071 s->proxy->id, s->srv->id);
2072 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002073 }
2074 }
2075 else if (s->proxy->options & PR_O_BIND_SRC) {
2076 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2077 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2078 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2079 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002080 send_log(s->proxy, LOG_EMERG,
2081 "Cannot bind to source address before connect() for server %s/%s.\n",
2082 s->proxy->id, s->srv->id);
2083 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002084 }
willy tarreaua1598082005-12-17 13:08:06 +01002085 }
2086
willy tarreaub1285d52005-12-18 01:20:14 +01002087 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2088 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2089
2090 if (errno == EAGAIN || errno == EADDRINUSE) {
2091 char *msg;
2092 if (errno == EAGAIN) /* no free ports left, try again later */
2093 msg = "no free ports";
2094 else
2095 msg = "local address already in use";
2096
2097 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002098 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002099 send_log(s->proxy, LOG_EMERG,
2100 "Connect() failed for server %s/%s: %s.\n",
2101 s->proxy->id, s->srv->id, msg);
2102 return SN_ERR_RESOURCE;
2103 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002104 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002105 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002106 return SN_ERR_SRVTO;
2107 } else {
2108 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002109 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002110 close(fd);
2111 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002112 }
2113 }
2114
willy tarreau5cbea6f2005-12-17 12:48:26 +01002115 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002116 fdtab[fd].read = &event_srv_read;
2117 fdtab[fd].write = &event_srv_write;
2118 fdtab[fd].state = FD_STCONN; /* connection in progress */
2119
2120 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002121#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2122 if (PrevReadEvent) {
2123 assert(!(FD_ISSET(fd, PrevReadEvent)));
2124 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2125 }
2126#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002127
2128 fd_insert(fd);
willy tarreaua647c702006-04-15 22:45:52 +02002129 s->srv->cur_sess++;
willy tarreau0f7af912005-12-17 12:21:26 +01002130
2131 if (s->proxy->contimeout)
2132 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2133 else
2134 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002135 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002136}
2137
2138/*
2139 * this function is called on a read event from a client socket.
2140 * It returns 0.
2141 */
2142int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002143 struct task *t = fdtab[fd].owner;
2144 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002145 struct buffer *b = s->req;
2146 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002147
willy tarreau12350152005-12-18 01:03:27 +01002148#ifdef DEBUG_FULL
2149 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2150#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002151
willy tarreau0f7af912005-12-17 12:21:26 +01002152 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002153#ifdef FILL_BUFFERS
2154 while (1)
2155#else
2156 do
2157#endif
2158 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002159 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2160 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002161 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002162 }
2163 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002164 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002165 }
2166 else {
2167 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002168 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2169 * since it means that the rewrite protection has been removed. This
2170 * implies that the if statement can be removed.
2171 */
2172 if (max > b->rlim - b->data)
2173 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002174 }
2175
2176 if (max == 0) { /* not anymore room to store data */
2177 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002178 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002179 }
2180
willy tarreau3242e862005-12-17 12:27:53 +01002181#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002182 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002183 int skerr;
2184 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002185
willy tarreau5cbea6f2005-12-17 12:48:26 +01002186 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2187 if (skerr)
2188 ret = -1;
2189 else
2190 ret = recv(fd, b->r, max, 0);
2191 }
willy tarreau3242e862005-12-17 12:27:53 +01002192#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002193 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002194#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002195 if (ret > 0) {
2196 b->r += ret;
2197 b->l += ret;
2198 s->res_cr = RES_DATA;
2199
2200 if (b->r == b->data + BUFSIZE) {
2201 b->r = b->data; /* wrap around the buffer */
2202 }
willy tarreaua1598082005-12-17 13:08:06 +01002203
2204 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002205 /* we hope to read more data or to get a close on next round */
2206 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002207 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002208 else if (ret == 0) {
2209 s->res_cr = RES_NULL;
2210 break;
2211 }
2212 else if (errno == EAGAIN) {/* ignore EAGAIN */
2213 break;
2214 }
2215 else {
2216 s->res_cr = RES_ERROR;
2217 fdtab[fd].state = FD_STERROR;
2218 break;
2219 }
2220 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002221#ifndef FILL_BUFFERS
2222 while (0);
2223#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002224 }
2225 else {
2226 s->res_cr = RES_ERROR;
2227 fdtab[fd].state = FD_STERROR;
2228 }
2229
willy tarreau5cbea6f2005-12-17 12:48:26 +01002230 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002231 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002232 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2233 else
2234 tv_eternity(&s->crexpire);
2235
2236 task_wakeup(&rq, t);
2237 }
willy tarreau0f7af912005-12-17 12:21:26 +01002238
willy tarreau0f7af912005-12-17 12:21:26 +01002239 return 0;
2240}
2241
2242
2243/*
2244 * this function is called on a read event from a server socket.
2245 * It returns 0.
2246 */
2247int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002248 struct task *t = fdtab[fd].owner;
2249 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002250 struct buffer *b = s->rep;
2251 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002252
willy tarreau12350152005-12-18 01:03:27 +01002253#ifdef DEBUG_FULL
2254 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2255#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002256
willy tarreau0f7af912005-12-17 12:21:26 +01002257 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002258#ifdef FILL_BUFFERS
2259 while (1)
2260#else
2261 do
2262#endif
2263 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002264 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2265 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002266 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002267 }
2268 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002269 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002270 }
2271 else {
2272 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002273 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2274 * since it means that the rewrite protection has been removed. This
2275 * implies that the if statement can be removed.
2276 */
2277 if (max > b->rlim - b->data)
2278 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002279 }
2280
2281 if (max == 0) { /* not anymore room to store data */
2282 FD_CLR(fd, StaticReadEvent);
2283 break;
2284 }
2285
willy tarreau3242e862005-12-17 12:27:53 +01002286#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002287 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002288 int skerr;
2289 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002290
willy tarreau5cbea6f2005-12-17 12:48:26 +01002291 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2292 if (skerr)
2293 ret = -1;
2294 else
2295 ret = recv(fd, b->r, max, 0);
2296 }
willy tarreau3242e862005-12-17 12:27:53 +01002297#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002298 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002299#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002300 if (ret > 0) {
2301 b->r += ret;
2302 b->l += ret;
2303 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002304
willy tarreau5cbea6f2005-12-17 12:48:26 +01002305 if (b->r == b->data + BUFSIZE) {
2306 b->r = b->data; /* wrap around the buffer */
2307 }
willy tarreaua1598082005-12-17 13:08:06 +01002308
2309 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002310 /* we hope to read more data or to get a close on next round */
2311 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002312 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002313 else if (ret == 0) {
2314 s->res_sr = RES_NULL;
2315 break;
2316 }
2317 else if (errno == EAGAIN) {/* ignore EAGAIN */
2318 break;
2319 }
2320 else {
2321 s->res_sr = RES_ERROR;
2322 fdtab[fd].state = FD_STERROR;
2323 break;
2324 }
2325 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002326#ifndef FILL_BUFFERS
2327 while (0);
2328#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002329 }
2330 else {
2331 s->res_sr = RES_ERROR;
2332 fdtab[fd].state = FD_STERROR;
2333 }
2334
willy tarreau5cbea6f2005-12-17 12:48:26 +01002335 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002336 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002337 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2338 else
2339 tv_eternity(&s->srexpire);
2340
2341 task_wakeup(&rq, t);
2342 }
willy tarreau0f7af912005-12-17 12:21:26 +01002343
willy tarreau0f7af912005-12-17 12:21:26 +01002344 return 0;
2345}
2346
2347/*
2348 * this function is called on a write event from a client socket.
2349 * It returns 0.
2350 */
2351int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002352 struct task *t = fdtab[fd].owner;
2353 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002354 struct buffer *b = s->rep;
2355 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002356
willy tarreau12350152005-12-18 01:03:27 +01002357#ifdef DEBUG_FULL
2358 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2359#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002360
2361 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002362 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002363 // max = BUFSIZE; BUG !!!!
2364 max = 0;
2365 }
2366 else if (b->r > b->w) {
2367 max = b->r - b->w;
2368 }
2369 else
2370 max = b->data + BUFSIZE - b->w;
2371
willy tarreau0f7af912005-12-17 12:21:26 +01002372 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002373 if (max == 0) {
2374 s->res_cw = RES_NULL;
2375 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002376 tv_eternity(&s->cwexpire);
2377 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002378 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002379 }
2380
willy tarreau3242e862005-12-17 12:27:53 +01002381#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002382 {
2383 int skerr;
2384 socklen_t lskerr = sizeof(skerr);
2385
2386 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2387 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002388 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002389 else
willy tarreau3242e862005-12-17 12:27:53 +01002390 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002391 }
willy tarreau3242e862005-12-17 12:27:53 +01002392#else
willy tarreau0f7af912005-12-17 12:21:26 +01002393 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002394#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002395
2396 if (ret > 0) {
2397 b->l -= ret;
2398 b->w += ret;
2399
2400 s->res_cw = RES_DATA;
2401
2402 if (b->w == b->data + BUFSIZE) {
2403 b->w = b->data; /* wrap around the buffer */
2404 }
2405 }
2406 else if (ret == 0) {
2407 /* nothing written, just make as if we were never called */
2408// s->res_cw = RES_NULL;
2409 return 0;
2410 }
2411 else if (errno == EAGAIN) /* ignore EAGAIN */
2412 return 0;
2413 else {
2414 s->res_cw = RES_ERROR;
2415 fdtab[fd].state = FD_STERROR;
2416 }
2417 }
2418 else {
2419 s->res_cw = RES_ERROR;
2420 fdtab[fd].state = FD_STERROR;
2421 }
2422
willy tarreaub1ff9db2005-12-17 13:51:03 +01002423 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002424 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002425 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2426 s->crexpire = s->cwexpire;
2427 }
willy tarreau0f7af912005-12-17 12:21:26 +01002428 else
2429 tv_eternity(&s->cwexpire);
2430
willy tarreau5cbea6f2005-12-17 12:48:26 +01002431 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002432 return 0;
2433}
2434
2435
2436/*
2437 * this function is called on a write event from a server socket.
2438 * It returns 0.
2439 */
2440int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002441 struct task *t = fdtab[fd].owner;
2442 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002443 struct buffer *b = s->req;
2444 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002445
willy tarreau12350152005-12-18 01:03:27 +01002446#ifdef DEBUG_FULL
2447 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2448#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002449
2450 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002451 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002452 // max = BUFSIZE; BUG !!!!
2453 max = 0;
2454 }
2455 else if (b->r > b->w) {
2456 max = b->r - b->w;
2457 }
2458 else
2459 max = b->data + BUFSIZE - b->w;
2460
willy tarreau0f7af912005-12-17 12:21:26 +01002461 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002462 if (max == 0) {
2463 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002464 if (s->srv_state == SV_STCONN) {
2465 int skerr;
2466 socklen_t lskerr = sizeof(skerr);
2467 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2468 if (skerr) {
2469 s->res_sw = RES_ERROR;
2470 fdtab[fd].state = FD_STERROR;
2471 task_wakeup(&rq, t);
2472 tv_eternity(&s->swexpire);
2473 FD_CLR(fd, StaticWriteEvent);
2474 return 0;
2475 }
2476 }
2477
willy tarreau0f7af912005-12-17 12:21:26 +01002478 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002479 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002480 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002481 tv_eternity(&s->swexpire);
2482 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002483 return 0;
2484 }
2485
willy tarreau3242e862005-12-17 12:27:53 +01002486#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002487 {
2488 int skerr;
2489 socklen_t lskerr = sizeof(skerr);
2490 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2491 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002492 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002493 else
willy tarreau3242e862005-12-17 12:27:53 +01002494 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002495 }
willy tarreau3242e862005-12-17 12:27:53 +01002496#else
willy tarreau0f7af912005-12-17 12:21:26 +01002497 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002498#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002499 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002500 if (ret > 0) {
2501 b->l -= ret;
2502 b->w += ret;
2503
2504 s->res_sw = RES_DATA;
2505
2506 if (b->w == b->data + BUFSIZE) {
2507 b->w = b->data; /* wrap around the buffer */
2508 }
2509 }
2510 else if (ret == 0) {
2511 /* nothing written, just make as if we were never called */
2512 // s->res_sw = RES_NULL;
2513 return 0;
2514 }
2515 else if (errno == EAGAIN) /* ignore EAGAIN */
2516 return 0;
2517 else {
2518 s->res_sw = RES_ERROR;
2519 fdtab[fd].state = FD_STERROR;
2520 }
2521 }
2522 else {
2523 s->res_sw = RES_ERROR;
2524 fdtab[fd].state = FD_STERROR;
2525 }
2526
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002527 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2528 * otherwise it could loop indefinitely !
2529 */
2530 if (s->srv_state != SV_STCONN) {
2531 if (s->proxy->srvtimeout) {
2532 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
2533 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2534 s->srexpire = s->swexpire;
2535 }
2536 else
2537 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002538 }
willy tarreau0f7af912005-12-17 12:21:26 +01002539
willy tarreau5cbea6f2005-12-17 12:48:26 +01002540 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002541 return 0;
2542}
2543
2544
2545/*
willy tarreaue39cd132005-12-17 13:00:18 +01002546 * returns a message to the client ; the connection is shut down for read,
2547 * and the request is cleared so that no server connection can be initiated.
2548 * The client must be in a valid state for this (HEADER, DATA ...).
2549 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002550 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002551 */
2552void client_retnclose(struct session *s, int len, const char *msg) {
2553 FD_CLR(s->cli_fd, StaticReadEvent);
2554 FD_SET(s->cli_fd, StaticWriteEvent);
2555 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002556 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002557 shutdown(s->cli_fd, SHUT_RD);
2558 s->cli_state = CL_STSHUTR;
2559 strcpy(s->rep->data, msg);
2560 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002561 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002562 s->rep->r += len;
2563 s->req->l = 0;
2564}
2565
2566
2567/*
2568 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002569 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002570 */
2571void client_return(struct session *s, int len, const char *msg) {
2572 strcpy(s->rep->data, msg);
2573 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002574 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002575 s->rep->r += len;
2576 s->req->l = 0;
2577}
2578
willy tarreau9fe663a2005-12-17 13:02:59 +01002579/*
2580 * send a log for the session when we have enough info about it
2581 */
2582void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002583 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002584 struct proxy *p = s->proxy;
2585 int log;
2586 char *uri;
2587 char *pxid;
2588 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002589 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002590
2591 /* This is a first attempt at a better logging system.
2592 * For now, we rely on send_log() to provide the date, although it obviously
2593 * is the date of the log and not of the request, and most fields are not
2594 * computed.
2595 */
2596
willy tarreaua1598082005-12-17 13:08:06 +01002597 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002598
willy tarreau8a86dbf2005-12-18 00:45:59 +01002599 if (s->cli_addr.ss_family == AF_INET)
2600 inet_ntop(AF_INET,
2601 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2602 pn, sizeof(pn));
2603 else
2604 inet_ntop(AF_INET6,
2605 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2606 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002607
willy tarreauc1cae632005-12-17 14:12:23 +01002608 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002609 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002610 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002611
willy tarreauc1cae632005-12-17 14:12:23 +01002612 tm = localtime(&s->logs.tv_accept.tv_sec);
2613 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002614 char tmpline[MAX_SYSLOG_LEN], *h;
2615 int hdr;
2616
2617 h = tmpline;
2618 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2619 *(h++) = ' ';
2620 *(h++) = '{';
2621 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2622 if (hdr)
2623 *(h++) = '|';
2624 if (s->req_cap[hdr] != NULL)
2625 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2626 }
2627 *(h++) = '}';
2628 }
2629
2630 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2631 *(h++) = ' ';
2632 *(h++) = '{';
2633 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2634 if (hdr)
2635 *(h++) = '|';
2636 if (s->rsp_cap[hdr] != NULL)
2637 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2638 }
2639 *(h++) = '}';
2640 }
2641
2642 if (h < tmpline + sizeof(tmpline) - 4) {
2643 *(h++) = ' ';
2644 *(h++) = '"';
2645 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2646 *(h++) = '"';
2647 }
2648 *h = '\0';
2649
willy tarreaua647c702006-04-15 22:45:52 +02002650 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%s%d %d %s%lld %s %s %c%c%c%c %d/%d/%d%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002651 pn,
2652 (s->cli_addr.ss_family == AF_INET) ?
2653 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2654 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002655 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2656 tm->tm_hour, tm->tm_min, tm->tm_sec,
2657 pxid, srv,
2658 s->logs.t_request,
2659 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2660 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002661 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2662 s->logs.status,
2663 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002664 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2665 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002666 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2667 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2668 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2669 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreaua647c702006-04-15 22:45:52 +02002670 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002671 }
2672 else {
willy tarreaua647c702006-04-15 22:45:52 +02002673 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c %d/%d/%d\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002674 pn,
2675 (s->cli_addr.ss_family == AF_INET) ?
2676 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2677 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002678 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2679 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002680 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002681 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002682 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2683 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002684 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002685 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreaua647c702006-04-15 22:45:52 +02002686 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002687 }
2688
2689 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002690}
2691
willy tarreaue39cd132005-12-17 13:00:18 +01002692
2693/*
willy tarreau0f7af912005-12-17 12:21:26 +01002694 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002695 * to an accept. It tries to accept as many connections as possible.
2696 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002697 */
2698int event_accept(int fd) {
2699 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002700 struct session *s;
2701 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002702 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01002703 int max_accept;
2704
2705 if (global.nbproc > 1)
2706 max_accept = 8; /* let other processes catch some connections too */
2707 else
2708 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01002709
willy tarreauc2becdc2006-03-19 19:36:48 +01002710 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002711 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002712 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002713
willy tarreaub1285d52005-12-18 01:20:14 +01002714 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2715 switch (errno) {
2716 case EAGAIN:
2717 case EINTR:
2718 case ECONNABORTED:
2719 return 0; /* nothing more to accept */
2720 case ENFILE:
2721 send_log(p, LOG_EMERG,
2722 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2723 p->id, maxfd);
2724 return 0;
2725 case EMFILE:
2726 send_log(p, LOG_EMERG,
2727 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2728 p->id, maxfd);
2729 return 0;
2730 case ENOBUFS:
2731 case ENOMEM:
2732 send_log(p, LOG_EMERG,
2733 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2734 p->id, maxfd);
2735 return 0;
2736 default:
2737 return 0;
2738 }
2739 }
willy tarreau0f7af912005-12-17 12:21:26 +01002740
willy tarreau5cbea6f2005-12-17 12:48:26 +01002741 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2742 Alert("out of memory in event_accept().\n");
2743 FD_CLR(fd, StaticReadEvent);
2744 p->state = PR_STIDLE;
2745 close(cfd);
2746 return 0;
2747 }
willy tarreau0f7af912005-12-17 12:21:26 +01002748
willy tarreaub1285d52005-12-18 01:20:14 +01002749 /* if this session comes from a known monitoring system, we want to ignore
2750 * it as soon as possible, which means closing it immediately for TCP.
2751 */
2752 s->flags = 0;
2753 if (addr.ss_family == AF_INET &&
2754 p->mon_mask.s_addr &&
2755 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2756 if (p->mode == PR_MODE_TCP) {
2757 close(cfd);
2758 pool_free(session, s);
2759 continue;
2760 }
2761 s->flags |= SN_MONITOR;
2762 }
2763
willy tarreau5cbea6f2005-12-17 12:48:26 +01002764 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2765 Alert("out of memory in event_accept().\n");
2766 FD_CLR(fd, StaticReadEvent);
2767 p->state = PR_STIDLE;
2768 close(cfd);
2769 pool_free(session, s);
2770 return 0;
2771 }
willy tarreau0f7af912005-12-17 12:21:26 +01002772
willy tarreau5cbea6f2005-12-17 12:48:26 +01002773 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002774 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002775 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2776 close(cfd);
2777 pool_free(task, t);
2778 pool_free(session, s);
2779 return 0;
2780 }
willy tarreau0f7af912005-12-17 12:21:26 +01002781
willy tarreau5cbea6f2005-12-17 12:48:26 +01002782 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2783 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2784 (char *) &one, sizeof(one)) == -1)) {
2785 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2786 close(cfd);
2787 pool_free(task, t);
2788 pool_free(session, s);
2789 return 0;
2790 }
willy tarreau0f7af912005-12-17 12:21:26 +01002791
willy tarreaub952e1d2005-12-18 01:31:20 +01002792 if (p->options & PR_O_TCP_CLI_KA)
2793 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2794
willy tarreau9fe663a2005-12-17 13:02:59 +01002795 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2796 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2797 t->state = TASK_IDLE;
2798 t->process = process_session;
2799 t->context = s;
2800
2801 s->task = t;
2802 s->proxy = p;
2803 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2804 s->srv_state = SV_STIDLE;
2805 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002806
willy tarreau9fe663a2005-12-17 13:02:59 +01002807 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2808 s->cli_fd = cfd;
2809 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002810 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002811 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002812
willy tarreaub1285d52005-12-18 01:20:14 +01002813 if (s->flags & SN_MONITOR)
2814 s->logs.logwait = 0;
2815 else
2816 s->logs.logwait = p->to_log;
2817
willy tarreaua1598082005-12-17 13:08:06 +01002818 s->logs.tv_accept = now;
2819 s->logs.t_request = -1;
2820 s->logs.t_connect = -1;
2821 s->logs.t_data = -1;
2822 s->logs.t_close = 0;
2823 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002824 s->logs.cli_cookie = NULL;
2825 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002826 s->logs.status = -1;
2827 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002828
willy tarreau2f6ba652005-12-17 13:57:42 +01002829 s->uniq_id = totalconn;
2830
willy tarreau4302f492005-12-18 01:00:37 +01002831 if (p->nb_req_cap > 0) {
2832 if ((s->req_cap =
2833 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2834 == NULL) { /* no memory */
2835 close(cfd); /* nothing can be done for this fd without memory */
2836 pool_free(task, t);
2837 pool_free(session, s);
2838 return 0;
2839 }
2840 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2841 }
2842 else
2843 s->req_cap = NULL;
2844
2845 if (p->nb_rsp_cap > 0) {
2846 if ((s->rsp_cap =
2847 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2848 == NULL) { /* no memory */
2849 if (s->req_cap != NULL)
2850 pool_free_to(p->req_cap_pool, s->req_cap);
2851 close(cfd); /* nothing can be done for this fd without memory */
2852 pool_free(task, t);
2853 pool_free(session, s);
2854 return 0;
2855 }
2856 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2857 }
2858 else
2859 s->rsp_cap = NULL;
2860
willy tarreau5cbea6f2005-12-17 12:48:26 +01002861 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2862 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002863 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002864 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002865
willy tarreau8a86dbf2005-12-18 00:45:59 +01002866 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002867 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002868 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002869 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002870
willy tarreau9fe663a2005-12-17 13:02:59 +01002871 if (p->to_log) {
2872 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002873 if (s->logs.logwait & LW_CLIP)
2874 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002875 sess_log(s);
2876 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002877 else if (s->cli_addr.ss_family == AF_INET) {
2878 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2879 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2880 sn, sizeof(sn)) &&
2881 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2882 pn, sizeof(pn))) {
2883 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2884 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2885 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2886 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2887 }
2888 }
2889 else {
2890 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2891 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2892 sn, sizeof(sn)) &&
2893 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2894 pn, sizeof(pn))) {
2895 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2896 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2897 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2898 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2899 }
2900 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002901 }
willy tarreau0f7af912005-12-17 12:21:26 +01002902
willy tarreau982249e2005-12-18 00:57:06 +01002903 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002904 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002905 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002906 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002907 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002908 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002909 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002910 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002911
willy tarreau8a86dbf2005-12-18 00:45:59 +01002912 if (s->cli_addr.ss_family == AF_INET) {
2913 char pn[INET_ADDRSTRLEN];
2914 inet_ntop(AF_INET,
2915 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2916 pn, sizeof(pn));
2917
2918 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2919 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2920 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2921 }
2922 else {
2923 char pn[INET6_ADDRSTRLEN];
2924 inet_ntop(AF_INET6,
2925 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2926 pn, sizeof(pn));
2927
2928 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2929 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2930 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2931 }
2932
willy tarreauef900ab2005-12-17 12:52:52 +01002933 write(1, trash, len);
2934 }
willy tarreau0f7af912005-12-17 12:21:26 +01002935
willy tarreau5cbea6f2005-12-17 12:48:26 +01002936 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002937 if (s->rsp_cap != NULL)
2938 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2939 if (s->req_cap != NULL)
2940 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002941 close(cfd); /* nothing can be done for this fd without memory */
2942 pool_free(task, t);
2943 pool_free(session, s);
2944 return 0;
2945 }
willy tarreau4302f492005-12-18 01:00:37 +01002946
willy tarreau5cbea6f2005-12-17 12:48:26 +01002947 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002948 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002949 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2950 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002951 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002952 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002953
willy tarreau5cbea6f2005-12-17 12:48:26 +01002954 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2955 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002956 if (s->rsp_cap != NULL)
2957 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2958 if (s->req_cap != NULL)
2959 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002960 close(cfd); /* nothing can be done for this fd without memory */
2961 pool_free(task, t);
2962 pool_free(session, s);
2963 return 0;
2964 }
2965 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002966 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002967 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 +01002968
willy tarreau5cbea6f2005-12-17 12:48:26 +01002969 fdtab[cfd].read = &event_cli_read;
2970 fdtab[cfd].write = &event_cli_write;
2971 fdtab[cfd].owner = t;
2972 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002973
willy tarreaub1285d52005-12-18 01:20:14 +01002974 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2975 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2976 /* Either we got a request from a monitoring system on an HTTP instance,
2977 * or we're in health check mode with the 'httpchk' option enabled. In
2978 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2979 */
2980 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2981 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2982 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002983 }
2984 else {
2985 FD_SET(cfd, StaticReadEvent);
2986 }
2987
willy tarreaub952e1d2005-12-18 01:31:20 +01002988#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2989 if (PrevReadEvent) {
2990 assert(!(FD_ISSET(cfd, PrevReadEvent)));
2991 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
2992 }
2993#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002994 fd_insert(cfd);
2995
2996 tv_eternity(&s->cnexpire);
2997 tv_eternity(&s->srexpire);
2998 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01002999 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003000 tv_eternity(&s->cwexpire);
3001
willy tarreaub1285d52005-12-18 01:20:14 +01003002 if (s->proxy->clitimeout) {
3003 if (FD_ISSET(cfd, StaticReadEvent))
3004 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3005 if (FD_ISSET(cfd, StaticWriteEvent))
3006 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3007 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003008
willy tarreaub1285d52005-12-18 01:20:14 +01003009 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003010
3011 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003012
3013 if (p->mode != PR_MODE_HEALTH)
3014 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003015
3016 p->nbconn++;
3017 actconn++;
3018 totalconn++;
3019
willy tarreaub952e1d2005-12-18 01:31:20 +01003020 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003021 } /* end of while (p->nbconn < p->maxconn) */
3022 return 0;
3023}
willy tarreau0f7af912005-12-17 12:21:26 +01003024
willy tarreau0f7af912005-12-17 12:21:26 +01003025
willy tarreau5cbea6f2005-12-17 12:48:26 +01003026/*
3027 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003028 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3029 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003030 * or -1 if an error occured.
3031 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003032int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003033 struct task *t = fdtab[fd].owner;
3034 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003035 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003036 socklen_t lskerr = sizeof(skerr);
3037
willy tarreau05be12b2006-03-19 19:35:00 +01003038 skerr = 1;
3039 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3040 || (skerr != 0)) {
3041 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003042 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003043 fdtab[fd].state = FD_STERROR;
3044 FD_CLR(fd, StaticWriteEvent);
3045 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003046 else if (s->result != -1) {
3047 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003048 if (s->proxy->options & PR_O_HTTP_CHK) {
3049 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003050 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003051 * so we'll send the request, and won't wake the checker up now.
3052 */
3053#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003054 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003055#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003056 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003057#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003058 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003059 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3060 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3061 return 0;
3062 }
willy tarreau05be12b2006-03-19 19:35:00 +01003063 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003064 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003065 FD_CLR(fd, StaticWriteEvent);
3066 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003067 }
3068 else {
3069 /* good TCP connection is enough */
3070 s->result = 1;
3071 }
3072 }
3073
3074 task_wakeup(&rq, t);
3075 return 0;
3076}
3077
willy tarreau0f7af912005-12-17 12:21:26 +01003078
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003079/*
3080 * This function is used only for server health-checks. It handles
3081 * the server's reply to an HTTP request. It returns 1 if the server replies
3082 * 2xx or 3xx (valid responses), or -1 in other cases.
3083 */
3084int event_srv_chk_r(int fd) {
3085 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003086 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003087 struct task *t = fdtab[fd].owner;
3088 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003089 int skerr;
3090 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003091
willy tarreaua4a583a2005-12-18 01:39:19 +01003092 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003093
willy tarreau05be12b2006-03-19 19:35:00 +01003094 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3095 if (!skerr) {
3096#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003097 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003098#else
willy tarreau05be12b2006-03-19 19:35:00 +01003099 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3100 * but the connection was closed on the remote end. Fortunately, recv still
3101 * works correctly and we don't need to do the getsockopt() on linux.
3102 */
3103 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003104#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003105
3106 if ((len >= sizeof("HTTP/1.0 000")) &&
3107 !memcmp(reply, "HTTP/1.", 7) &&
3108 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3109 result = 1;
3110 }
3111
3112 if (result == -1)
3113 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003114
3115 if (s->result != -1)
3116 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003117
3118 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003119 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003120 return 0;
3121}
3122
3123
3124/*
3125 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3126 * and moves <end> just after the end of <str>.
3127 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3128 * the shift value (positive or negative) is returned.
3129 * If there's no space left, the move is not done.
3130 *
3131 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003132int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003133 int delta;
3134 int len;
3135
3136 len = strlen(str);
3137 delta = len - (end - pos);
3138
3139 if (delta + b->r >= b->data + BUFSIZE)
3140 return 0; /* no space left */
3141
3142 /* first, protect the end of the buffer */
3143 memmove(end + delta, end, b->data + b->l - end);
3144
3145 /* now, copy str over pos */
3146 memcpy(pos, str,len);
3147
willy tarreau5cbea6f2005-12-17 12:48:26 +01003148 /* we only move data after the displaced zone */
3149 if (b->r > pos) b->r += delta;
3150 if (b->w > pos) b->w += delta;
3151 if (b->h > pos) b->h += delta;
3152 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003153 b->l += delta;
3154
3155 return delta;
3156}
3157
willy tarreau8337c6b2005-12-17 13:41:01 +01003158/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003159 * len is 0.
3160 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003161int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003162 int delta;
3163
3164 delta = len - (end - pos);
3165
3166 if (delta + b->r >= b->data + BUFSIZE)
3167 return 0; /* no space left */
3168
Willy TARREAUe78ae262006-01-08 01:24:12 +01003169 if (b->data + b->l < end)
3170 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3171 return 0;
3172
willy tarreau0f7af912005-12-17 12:21:26 +01003173 /* first, protect the end of the buffer */
3174 memmove(end + delta, end, b->data + b->l - end);
3175
3176 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003177 if (len)
3178 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003179
willy tarreau5cbea6f2005-12-17 12:48:26 +01003180 /* we only move data after the displaced zone */
3181 if (b->r > pos) b->r += delta;
3182 if (b->w > pos) b->w += delta;
3183 if (b->h > pos) b->h += delta;
3184 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003185 b->l += delta;
3186
3187 return delta;
3188}
3189
3190
3191int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3192 char *old_dst = dst;
3193
3194 while (*str) {
3195 if (*str == '\\') {
3196 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003197 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003198 int len, num;
3199
3200 num = *str - '0';
3201 str++;
3202
willy tarreau8a86dbf2005-12-18 00:45:59 +01003203 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003204 len = matches[num].rm_eo - matches[num].rm_so;
3205 memcpy(dst, src + matches[num].rm_so, len);
3206 dst += len;
3207 }
3208
3209 }
3210 else if (*str == 'x') {
3211 unsigned char hex1, hex2;
3212 str++;
3213
willy tarreauc1f47532005-12-18 01:08:26 +01003214 hex1 = toupper(*str++) - '0';
3215 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003216
3217 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3218 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3219 *dst++ = (hex1<<4) + hex2;
3220 }
3221 else
3222 *dst++ = *str++;
3223 }
3224 else
3225 *dst++ = *str++;
3226 }
3227 *dst = 0;
3228 return dst - old_dst;
3229}
3230
willy tarreauc1f47532005-12-18 01:08:26 +01003231static int ishex(char s)
3232{
3233 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3234}
3235
3236/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3237char *check_replace_string(char *str)
3238{
3239 char *err = NULL;
3240 while (*str) {
3241 if (*str == '\\') {
3242 err = str; /* in case of a backslash, we return the pointer to it */
3243 str++;
3244 if (!*str)
3245 return err;
3246 else if (isdigit((int)*str))
3247 err = NULL;
3248 else if (*str == 'x') {
3249 str++;
3250 if (!ishex(*str))
3251 return err;
3252 str++;
3253 if (!ishex(*str))
3254 return err;
3255 err = NULL;
3256 }
3257 else {
3258 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3259 err = NULL;
3260 }
3261 }
3262 str++;
3263 }
3264 return err;
3265}
3266
3267
willy tarreau9fe663a2005-12-17 13:02:59 +01003268
willy tarreau0f7af912005-12-17 12:21:26 +01003269/*
3270 * manages the client FSM and its socket. BTW, it also tries to handle the
3271 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3272 * 0 else.
3273 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003274int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003275 int s = t->srv_state;
3276 int c = t->cli_state;
3277 struct buffer *req = t->req;
3278 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003279 int method_checked = 0;
3280 appsess *asession_temp = NULL;
3281 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003282
willy tarreau750a4722005-12-17 13:21:24 +01003283#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003284 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3285 cli_stnames[c], srv_stnames[s],
3286 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3287 t->crexpire.tv_sec, t->crexpire.tv_usec,
3288 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003289#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003290 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3291 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3292 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3293 //);
3294 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003295 /* now parse the partial (or complete) headers */
3296 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3297 char *ptr;
3298 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003299 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003300
willy tarreau5cbea6f2005-12-17 12:48:26 +01003301 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003302
willy tarreau0f7af912005-12-17 12:21:26 +01003303 /* look for the end of the current header */
3304 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3305 ptr++;
3306
willy tarreau5cbea6f2005-12-17 12:48:26 +01003307 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003308 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02003309
3310 /*
3311 * first, let's check that it's not a leading empty line, in
3312 * which case we'll ignore and remove it (according to RFC2616).
3313 */
3314 if (req->h == req->data) {
3315 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3316 if (ptr > req->r - 2) {
3317 /* this is a partial header, let's wait for more to come */
3318 req->lr = ptr;
3319 break;
3320 }
3321
3322 /* now we know that *ptr is either \r or \n,
3323 * and that there are at least 1 char after it.
3324 */
3325 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3326 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3327 else
3328 req->lr = ptr + 2; /* \r\n or \n\r */
3329 /* ignore empty leading lines */
3330 buffer_replace2(req, req->h, req->lr, NULL, 0);
3331 req->h = req->lr;
3332 continue;
3333 }
3334
willy tarreau5cbea6f2005-12-17 12:48:26 +01003335 /* we can only get here after an end of headers */
3336 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003337
willy tarreaue39cd132005-12-17 13:00:18 +01003338 if (t->flags & SN_CLDENY) {
3339 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003340 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003341 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003342 if (!(t->flags & SN_ERR_MASK))
3343 t->flags |= SN_ERR_PRXCOND;
3344 if (!(t->flags & SN_FINST_MASK))
3345 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003346 return 1;
3347 }
3348
willy tarreau5cbea6f2005-12-17 12:48:26 +01003349 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003350 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3351 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003352 }
willy tarreau0f7af912005-12-17 12:21:26 +01003353
willy tarreau9fe663a2005-12-17 13:02:59 +01003354 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003355 if (t->cli_addr.ss_family == AF_INET) {
3356 unsigned char *pn;
3357 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3358 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3359 pn[0], pn[1], pn[2], pn[3]);
3360 buffer_replace2(req, req->h, req->h, trash, len);
3361 }
3362 else if (t->cli_addr.ss_family == AF_INET6) {
3363 char pn[INET6_ADDRSTRLEN];
3364 inet_ntop(AF_INET6,
3365 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3366 pn, sizeof(pn));
3367 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3368 buffer_replace2(req, req->h, req->h, trash, len);
3369 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003370 }
3371
willy tarreau25c4ea52005-12-18 00:49:49 +01003372 /* add a "connection: close" line if needed */
3373 if (t->proxy->options & PR_O_HTTP_CLOSE)
3374 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3375
willy tarreau982249e2005-12-18 00:57:06 +01003376 if (!memcmp(req->data, "POST ", 5)) {
3377 /* this is a POST request, which is not cacheable by default */
3378 t->flags |= SN_POST;
3379 }
willy tarreaucd878942005-12-17 13:27:43 +01003380
willy tarreau5cbea6f2005-12-17 12:48:26 +01003381 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003382 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003383
willy tarreau750a4722005-12-17 13:21:24 +01003384 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003385 /* FIXME: we'll set the client in a wait state while we try to
3386 * connect to the server. Is this really needed ? wouldn't it be
3387 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003388 //FD_CLR(t->cli_fd, StaticReadEvent);
3389 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003390
3391 /* FIXME: if we break here (as up to 1.1.23), having the client
3392 * shutdown its connection can lead to an abort further.
3393 * it's better to either return 1 or even jump directly to the
3394 * data state which will save one schedule.
3395 */
3396 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003397
3398 if (!t->proxy->clitimeout ||
3399 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3400 /* If the client has no timeout, or if the server is not ready yet,
3401 * and we know for sure that it can expire, then it's cleaner to
3402 * disable the timeout on the client side so that too low values
3403 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003404 *
3405 * FIXME-20050705: the server needs a way to re-enable this time-out
3406 * when it switches its state, otherwise a client can stay connected
3407 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003408 */
3409 tv_eternity(&t->crexpire);
3410
willy tarreau197e8ec2005-12-17 14:10:59 +01003411 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003412 }
willy tarreau0f7af912005-12-17 12:21:26 +01003413
Willy TARREAU13032e72006-03-12 17:31:45 +01003414 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3415 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003416 /* this is a partial header, let's wait for more to come */
3417 req->lr = ptr;
3418 break;
3419 }
willy tarreau0f7af912005-12-17 12:21:26 +01003420
willy tarreau5cbea6f2005-12-17 12:48:26 +01003421 /* now we know that *ptr is either \r or \n,
3422 * and that there are at least 1 char after it.
3423 */
3424 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3425 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3426 else
3427 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003428
willy tarreau5cbea6f2005-12-17 12:48:26 +01003429 /*
3430 * now we know that we have a full header ; we can do whatever
3431 * we want with these pointers :
3432 * req->h = beginning of header
3433 * ptr = end of header (first \r or \n)
3434 * req->lr = beginning of next line (next rep->h)
3435 * req->r = end of data (not used at this stage)
3436 */
willy tarreau0f7af912005-12-17 12:21:26 +01003437
willy tarreau12350152005-12-18 01:03:27 +01003438 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3439 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3440 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3441
3442 /* skip ; */
3443 request_line++;
3444
3445 /* look if we have a jsessionid */
3446
3447 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3448
3449 /* skip jsessionid= */
3450 request_line += t->proxy->appsession_name_len + 1;
3451
3452 /* First try if we allready have an appsession */
3453 asession_temp = &local_asession;
3454
3455 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3456 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3457 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3458 return 0;
3459 }
3460
3461 /* Copy the sessionid */
3462 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3463 asession_temp->sessid[t->proxy->appsession_len] = 0;
3464 asession_temp->serverid = NULL;
3465
3466 /* only do insert, if lookup fails */
3467 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3468 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3469 Alert("Not enough memory process_cli():asession:calloc().\n");
3470 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3471 return 0;
3472 }
3473 asession_temp->sessid = local_asession.sessid;
3474 asession_temp->serverid = local_asession.serverid;
3475 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003476 } /* end if (chtbl_lookup()) */
3477 else {
willy tarreau12350152005-12-18 01:03:27 +01003478 /*free wasted memory;*/
3479 pool_free_to(apools.sessid, local_asession.sessid);
3480 }
3481
3482 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3483 asession_temp->request_count++;
3484
3485#if defined(DEBUG_HASH)
3486 print_table(&(t->proxy->htbl_proxy));
3487#endif
3488
3489 if (asession_temp->serverid == NULL) {
3490 Alert("Found Application Session without matching server.\n");
3491 } else {
3492 struct server *srv = t->proxy->srv;
3493 while (srv) {
3494 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3495 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3496 /* we found the server and it's usable */
3497 t->flags &= ~SN_CK_MASK;
3498 t->flags |= SN_CK_VALID | SN_DIRECT;
3499 t->srv = srv;
3500 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003501 } else {
willy tarreau12350152005-12-18 01:03:27 +01003502 t->flags &= ~SN_CK_MASK;
3503 t->flags |= SN_CK_DOWN;
3504 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003505 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003506 srv = srv->next;
3507 }/* end while(srv) */
3508 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003509 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003510 else {
3511 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3512 }
willy tarreau598da412005-12-18 01:07:29 +01003513 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003514 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003515 else{
3516 //printf("No Methode-Header with Session-String\n");
3517 }
3518
willy tarreau8337c6b2005-12-17 13:41:01 +01003519 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003520 /* we have a complete HTTP request that we must log */
3521 int urilen;
3522
willy tarreaua1598082005-12-17 13:08:06 +01003523 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003524 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003525 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003526 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003527 if (!(t->flags & SN_ERR_MASK))
3528 t->flags |= SN_ERR_PRXCOND;
3529 if (!(t->flags & SN_FINST_MASK))
3530 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003531 return 1;
3532 }
3533
3534 urilen = ptr - req->h;
3535 if (urilen >= REQURI_LEN)
3536 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003537 memcpy(t->logs.uri, req->h, urilen);
3538 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003539
willy tarreaua1598082005-12-17 13:08:06 +01003540 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003541 sess_log(t);
3542 }
willy tarreau4302f492005-12-18 01:00:37 +01003543 else if (t->logs.logwait & LW_REQHDR) {
3544 struct cap_hdr *h;
3545 int len;
3546 for (h = t->proxy->req_cap; h; h = h->next) {
3547 if ((h->namelen + 2 <= ptr - req->h) &&
3548 (req->h[h->namelen] == ':') &&
3549 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3550
3551 if (t->req_cap[h->index] == NULL)
3552 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3553
3554 len = ptr - (req->h + h->namelen + 2);
3555 if (len > h->len)
3556 len = h->len;
3557
3558 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3559 t->req_cap[h->index][len]=0;
3560 }
3561 }
3562
3563 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003564
willy tarreau5cbea6f2005-12-17 12:48:26 +01003565 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003566
willy tarreau982249e2005-12-18 00:57:06 +01003567 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003568 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003569 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 +01003570 max = ptr - req->h;
3571 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003572 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003573 trash[len++] = '\n';
3574 write(1, trash, len);
3575 }
willy tarreau0f7af912005-12-17 12:21:26 +01003576
willy tarreau25c4ea52005-12-18 00:49:49 +01003577
3578 /* remove "connection: " if needed */
3579 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3580 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3581 delete_header = 1;
3582 }
3583
willy tarreau5cbea6f2005-12-17 12:48:26 +01003584 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003585 if (!delete_header && t->proxy->req_exp != NULL
3586 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003587 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003588 char term;
3589
3590 term = *ptr;
3591 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003592 exp = t->proxy->req_exp;
3593 do {
3594 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3595 switch (exp->action) {
3596 case ACT_ALLOW:
3597 if (!(t->flags & SN_CLDENY))
3598 t->flags |= SN_CLALLOW;
3599 break;
3600 case ACT_REPLACE:
3601 if (!(t->flags & SN_CLDENY)) {
3602 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3603 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3604 }
3605 break;
3606 case ACT_REMOVE:
3607 if (!(t->flags & SN_CLDENY))
3608 delete_header = 1;
3609 break;
3610 case ACT_DENY:
3611 if (!(t->flags & SN_CLALLOW))
3612 t->flags |= SN_CLDENY;
3613 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003614 case ACT_PASS: /* we simply don't deny this one */
3615 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003616 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003617 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003618 }
willy tarreaue39cd132005-12-17 13:00:18 +01003619 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003620 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003621 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003622
willy tarreau240afa62005-12-17 13:14:35 +01003623 /* Now look for cookies. Conforming to RFC2109, we have to support
3624 * attributes whose name begin with a '$', and associate them with
3625 * the right cookie, if we want to delete this cookie.
3626 * So there are 3 cases for each cookie read :
3627 * 1) it's a special attribute, beginning with a '$' : ignore it.
3628 * 2) it's a server id cookie that we *MAY* want to delete : save
3629 * some pointers on it (last semi-colon, beginning of cookie...)
3630 * 3) it's an application cookie : we *MAY* have to delete a previous
3631 * "special" cookie.
3632 * At the end of loop, if a "special" cookie remains, we may have to
3633 * remove it. If no application cookie persists in the header, we
3634 * *MUST* delete it
3635 */
willy tarreau12350152005-12-18 01:03:27 +01003636 if (!delete_header &&
3637 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003638 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003639 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003640 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003641 char *del_colon, *del_cookie, *colon;
3642 int app_cookies;
3643
willy tarreau5cbea6f2005-12-17 12:48:26 +01003644 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003645 colon = p1;
3646 /* del_cookie == NULL => nothing to be deleted */
3647 del_colon = del_cookie = NULL;
3648 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003649
3650 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003651 /* skip spaces and colons, but keep an eye on these ones */
3652 while (p1 < ptr) {
3653 if (*p1 == ';' || *p1 == ',')
3654 colon = p1;
3655 else if (!isspace((int)*p1))
3656 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003657 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003658 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003659
3660 if (p1 == ptr)
3661 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003662
3663 /* p1 is at the beginning of the cookie name */
3664 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003665 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003666 p2++;
3667
3668 if (p2 == ptr)
3669 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003670
3671 p3 = p2 + 1; /* skips the '=' sign */
3672 if (p3 == ptr)
3673 break;
3674
willy tarreau240afa62005-12-17 13:14:35 +01003675 p4 = p3;
3676 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003677 p4++;
3678
3679 /* here, we have the cookie name between p1 and p2,
3680 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003681 * we can process it :
3682 *
3683 * Cookie: NAME=VALUE;
3684 * | || || |
3685 * | || || +--> p4
3686 * | || |+-------> p3
3687 * | || +--------> p2
3688 * | |+------------> p1
3689 * | +-------------> colon
3690 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003691 */
3692
willy tarreau240afa62005-12-17 13:14:35 +01003693 if (*p1 == '$') {
3694 /* skip this one */
3695 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003696 else {
3697 /* first, let's see if we want to capture it */
3698 if (t->proxy->capture_name != NULL &&
3699 t->logs.cli_cookie == NULL &&
3700 (p4 - p1 >= t->proxy->capture_namelen) &&
3701 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3702 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003703
willy tarreau8337c6b2005-12-17 13:41:01 +01003704 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3705 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003706 } else {
3707 if (log_len > t->proxy->capture_len)
3708 log_len = t->proxy->capture_len;
3709 memcpy(t->logs.cli_cookie, p1, log_len);
3710 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003711 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003712 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003713
3714 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3715 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3716 /* Cool... it's the right one */
3717 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003718 char *delim;
3719
3720 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3721 * have the server ID betweek p3 and delim, and the original cookie between
3722 * delim+1 and p4. Otherwise, delim==p4 :
3723 *
3724 * Cookie: NAME=SRV~VALUE;
3725 * | || || | |
3726 * | || || | +--> p4
3727 * | || || +--------> delim
3728 * | || |+-----------> p3
3729 * | || +------------> p2
3730 * | |+----------------> p1
3731 * | +-----------------> colon
3732 * +------------------------> req->h
3733 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003734
willy tarreau0174f312005-12-18 01:02:42 +01003735 if (t->proxy->options & PR_O_COOK_PFX) {
3736 for (delim = p3; delim < p4; delim++)
3737 if (*delim == COOKIE_DELIM)
3738 break;
3739 }
3740 else
3741 delim = p4;
3742
3743
3744 /* Here, we'll look for the first running server which supports the cookie.
3745 * This allows to share a same cookie between several servers, for example
3746 * to dedicate backup servers to specific servers only.
3747 */
3748 while (srv) {
3749 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3750 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3751 /* we found the server and it's usable */
3752 t->flags &= ~SN_CK_MASK;
3753 t->flags |= SN_CK_VALID | SN_DIRECT;
3754 t->srv = srv;
3755 break;
willy tarreau12350152005-12-18 01:03:27 +01003756 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003757 /* we found a server, but it's down */
3758 t->flags &= ~SN_CK_MASK;
3759 t->flags |= SN_CK_DOWN;
3760 }
3761 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003762 srv = srv->next;
3763 }
3764
willy tarreau0174f312005-12-18 01:02:42 +01003765 if (!srv && !(t->flags & SN_CK_DOWN)) {
3766 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003767 t->flags &= ~SN_CK_MASK;
3768 t->flags |= SN_CK_INVALID;
3769 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003770
willy tarreau0174f312005-12-18 01:02:42 +01003771 /* depending on the cookie mode, we may have to either :
3772 * - delete the complete cookie if we're in insert+indirect mode, so that
3773 * the server never sees it ;
3774 * - remove the server id from the cookie value, and tag the cookie as an
3775 * application cookie so that it does not get accidentely removed later,
3776 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003777 */
willy tarreau0174f312005-12-18 01:02:42 +01003778 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3779 buffer_replace2(req, p3, delim + 1, NULL, 0);
3780 p4 -= (delim + 1 - p3);
3781 ptr -= (delim + 1 - p3);
3782 del_cookie = del_colon = NULL;
3783 app_cookies++; /* protect the header from deletion */
3784 }
3785 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003786 (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 +01003787 del_cookie = p1;
3788 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003789 }
willy tarreau12350152005-12-18 01:03:27 +01003790 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003791 /* now we know that we must keep this cookie since it's
3792 * not ours. But if we wanted to delete our cookie
3793 * earlier, we cannot remove the complete header, but we
3794 * can remove the previous block itself.
3795 */
3796 app_cookies++;
3797
3798 if (del_cookie != NULL) {
3799 buffer_replace2(req, del_cookie, p1, NULL, 0);
3800 p4 -= (p1 - del_cookie);
3801 ptr -= (p1 - del_cookie);
3802 del_cookie = del_colon = NULL;
3803 }
willy tarreau240afa62005-12-17 13:14:35 +01003804 }
willy tarreau12350152005-12-18 01:03:27 +01003805
3806 if ((t->proxy->appsession_name != NULL) &&
3807 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3808 /* first, let's see if the cookie is our appcookie*/
3809
3810 /* Cool... it's the right one */
3811
3812 asession_temp = &local_asession;
3813
3814 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3815 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3816 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3817 return 0;
3818 }
3819
3820 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3821 asession_temp->sessid[t->proxy->appsession_len] = 0;
3822 asession_temp->serverid = NULL;
3823
3824 /* only do insert, if lookup fails */
3825 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3826 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3827 Alert("Not enough memory process_cli():asession:calloc().\n");
3828 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3829 return 0;
3830 }
3831
3832 asession_temp->sessid = local_asession.sessid;
3833 asession_temp->serverid = local_asession.serverid;
3834 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3835 }
3836 else{
3837 /* free wasted memory */
3838 pool_free_to(apools.sessid, local_asession.sessid);
3839 }
3840
3841 if (asession_temp->serverid == NULL) {
3842 Alert("Found Application Session without matching server.\n");
3843 } else {
3844 struct server *srv = t->proxy->srv;
3845 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003846 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003847 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3848 /* we found the server and it's usable */
3849 t->flags &= ~SN_CK_MASK;
3850 t->flags |= SN_CK_VALID | SN_DIRECT;
3851 t->srv = srv;
3852 break;
3853 } else {
3854 t->flags &= ~SN_CK_MASK;
3855 t->flags |= SN_CK_DOWN;
3856 }
3857 }
3858 srv = srv->next;
3859 }/* end while(srv) */
3860 }/* end else if server == NULL */
3861
3862 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003863 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003864 }
willy tarreau240afa62005-12-17 13:14:35 +01003865
willy tarreau5cbea6f2005-12-17 12:48:26 +01003866 /* we'll have to look for another cookie ... */
3867 p1 = p4;
3868 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003869
3870 /* There's no more cookie on this line.
3871 * We may have marked the last one(s) for deletion.
3872 * We must do this now in two ways :
3873 * - if there is no app cookie, we simply delete the header ;
3874 * - if there are app cookies, we must delete the end of the
3875 * string properly, including the colon/semi-colon before
3876 * the cookie name.
3877 */
3878 if (del_cookie != NULL) {
3879 if (app_cookies) {
3880 buffer_replace2(req, del_colon, ptr, NULL, 0);
3881 /* WARNING! <ptr> becomes invalid for now. If some code
3882 * below needs to rely on it before the end of the global
3883 * header loop, we need to correct it with this code :
3884 * ptr = del_colon;
3885 */
3886 }
3887 else
3888 delete_header = 1;
3889 }
3890 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003891
3892 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003893 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003894 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003895 }
willy tarreau240afa62005-12-17 13:14:35 +01003896 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3897
willy tarreau5cbea6f2005-12-17 12:48:26 +01003898 req->h = req->lr;
3899 } /* while (req->lr < req->r) */
3900
3901 /* end of header processing (even if incomplete) */
3902
willy tarreauef900ab2005-12-17 12:52:52 +01003903 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3904 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3905 * full. We cannot loop here since event_cli_read will disable it only if
3906 * req->l == rlim-data
3907 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003908 FD_SET(t->cli_fd, StaticReadEvent);
3909 if (t->proxy->clitimeout)
3910 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3911 else
3912 tv_eternity(&t->crexpire);
3913 }
3914
willy tarreaue39cd132005-12-17 13:00:18 +01003915 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003916 * won't be able to free more later, so the session will never terminate.
3917 */
willy tarreaue39cd132005-12-17 13:00:18 +01003918 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003919 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003920 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003921 if (!(t->flags & SN_ERR_MASK))
3922 t->flags |= SN_ERR_PRXCOND;
3923 if (!(t->flags & SN_FINST_MASK))
3924 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003925 return 1;
3926 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003927 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003928 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003929 tv_eternity(&t->crexpire);
3930 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003931 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003932 if (!(t->flags & SN_ERR_MASK))
3933 t->flags |= SN_ERR_CLICL;
3934 if (!(t->flags & SN_FINST_MASK))
3935 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003936 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003937 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003938 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3939
3940 /* read timeout : give up with an error message.
3941 */
3942 t->logs.status = 408;
3943 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003944 if (!(t->flags & SN_ERR_MASK))
3945 t->flags |= SN_ERR_CLITO;
3946 if (!(t->flags & SN_FINST_MASK))
3947 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003948 return 1;
3949 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003950
3951 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003952 }
3953 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003954 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003955 /* FIXME: this error handling is partly buggy because we always report
3956 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3957 * or HEADER phase. BTW, it's not logical to expire the client while
3958 * we're waiting for the server to connect.
3959 */
willy tarreau0f7af912005-12-17 12:21:26 +01003960 /* read or write error */
3961 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003962 tv_eternity(&t->crexpire);
3963 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003964 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003965 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003966 if (!(t->flags & SN_ERR_MASK))
3967 t->flags |= SN_ERR_CLICL;
3968 if (!(t->flags & SN_FINST_MASK))
3969 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003970 return 1;
3971 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003972 /* last read, or end of server write */
3973 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003974 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003975 tv_eternity(&t->crexpire);
3976 shutdown(t->cli_fd, SHUT_RD);
3977 t->cli_state = CL_STSHUTR;
3978 return 1;
3979 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003980 /* last server read and buffer empty */
3981 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003982 FD_CLR(t->cli_fd, StaticWriteEvent);
3983 tv_eternity(&t->cwexpire);
3984 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003985 /* We must ensure that the read part is still alive when switching
3986 * to shutw */
3987 FD_SET(t->cli_fd, StaticReadEvent);
3988 if (t->proxy->clitimeout)
3989 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003990 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003991 //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 +01003992 return 1;
3993 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003994 /* read timeout */
3995 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3996 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003997 tv_eternity(&t->crexpire);
3998 shutdown(t->cli_fd, SHUT_RD);
3999 t->cli_state = CL_STSHUTR;
4000 if (!(t->flags & SN_ERR_MASK))
4001 t->flags |= SN_ERR_CLITO;
4002 if (!(t->flags & SN_FINST_MASK))
4003 t->flags |= SN_FINST_D;
4004 return 1;
4005 }
4006 /* write timeout */
4007 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4008 FD_CLR(t->cli_fd, StaticWriteEvent);
4009 tv_eternity(&t->cwexpire);
4010 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004011 /* We must ensure that the read part is still alive when switching
4012 * to shutw */
4013 FD_SET(t->cli_fd, StaticReadEvent);
4014 if (t->proxy->clitimeout)
4015 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4016
willy tarreau036e1ce2005-12-17 13:46:33 +01004017 t->cli_state = CL_STSHUTW;
4018 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004019 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01004020 if (!(t->flags & SN_FINST_MASK))
4021 t->flags |= SN_FINST_D;
4022 return 1;
4023 }
willy tarreau0f7af912005-12-17 12:21:26 +01004024
willy tarreauc58fc692005-12-17 14:13:08 +01004025 if (req->l >= req->rlim - req->data) {
4026 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004027 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004028 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004029 FD_CLR(t->cli_fd, StaticReadEvent);
4030 tv_eternity(&t->crexpire);
4031 }
4032 }
4033 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004034 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004035 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4036 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004037 if (!t->proxy->clitimeout ||
4038 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4039 /* If the client has no timeout, or if the server not ready yet, and we
4040 * know for sure that it can expire, then it's cleaner to disable the
4041 * timeout on the client side so that too low values cannot make the
4042 * sessions abort too early.
4043 */
willy tarreau0f7af912005-12-17 12:21:26 +01004044 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004045 else
4046 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004047 }
4048 }
4049
4050 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004051 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004052 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4053 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4054 tv_eternity(&t->cwexpire);
4055 }
4056 }
4057 else { /* buffer not empty */
4058 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4059 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004060 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004061 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004062 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4063 t->crexpire = t->cwexpire;
4064 }
willy tarreau0f7af912005-12-17 12:21:26 +01004065 else
4066 tv_eternity(&t->cwexpire);
4067 }
4068 }
4069 return 0; /* other cases change nothing */
4070 }
4071 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004072 if (t->res_cw == RES_ERROR) {
4073 tv_eternity(&t->cwexpire);
4074 fd_delete(t->cli_fd);
4075 t->cli_state = CL_STCLOSE;
4076 if (!(t->flags & SN_ERR_MASK))
4077 t->flags |= SN_ERR_CLICL;
4078 if (!(t->flags & SN_FINST_MASK))
4079 t->flags |= SN_FINST_D;
4080 return 1;
4081 }
4082 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004083 tv_eternity(&t->cwexpire);
4084 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004085 t->cli_state = CL_STCLOSE;
4086 return 1;
4087 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004088 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4089 tv_eternity(&t->cwexpire);
4090 fd_delete(t->cli_fd);
4091 t->cli_state = CL_STCLOSE;
4092 if (!(t->flags & SN_ERR_MASK))
4093 t->flags |= SN_ERR_CLITO;
4094 if (!(t->flags & SN_FINST_MASK))
4095 t->flags |= SN_FINST_D;
4096 return 1;
4097 }
willy tarreau0f7af912005-12-17 12:21:26 +01004098 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004099 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004100 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4101 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4102 tv_eternity(&t->cwexpire);
4103 }
4104 }
4105 else { /* buffer not empty */
4106 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4107 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004108 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004109 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004110 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4111 t->crexpire = t->cwexpire;
4112 }
willy tarreau0f7af912005-12-17 12:21:26 +01004113 else
4114 tv_eternity(&t->cwexpire);
4115 }
4116 }
4117 return 0;
4118 }
4119 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004120 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004121 tv_eternity(&t->crexpire);
4122 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004123 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004124 if (!(t->flags & SN_ERR_MASK))
4125 t->flags |= SN_ERR_CLICL;
4126 if (!(t->flags & SN_FINST_MASK))
4127 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004128 return 1;
4129 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004130 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4131 tv_eternity(&t->crexpire);
4132 fd_delete(t->cli_fd);
4133 t->cli_state = CL_STCLOSE;
4134 return 1;
4135 }
4136 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4137 tv_eternity(&t->crexpire);
4138 fd_delete(t->cli_fd);
4139 t->cli_state = CL_STCLOSE;
4140 if (!(t->flags & SN_ERR_MASK))
4141 t->flags |= SN_ERR_CLITO;
4142 if (!(t->flags & SN_FINST_MASK))
4143 t->flags |= SN_FINST_D;
4144 return 1;
4145 }
willy tarreauef900ab2005-12-17 12:52:52 +01004146 else if (req->l >= req->rlim - req->data) {
4147 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004148
4149 /* FIXME-20050705: is it possible for a client to maintain a session
4150 * after the timeout by sending more data after it receives a close ?
4151 */
4152
willy tarreau0f7af912005-12-17 12:21:26 +01004153 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004154 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004155 FD_CLR(t->cli_fd, StaticReadEvent);
4156 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004157 //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 +01004158 }
4159 }
4160 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004161 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004162 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4163 FD_SET(t->cli_fd, StaticReadEvent);
4164 if (t->proxy->clitimeout)
4165 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4166 else
4167 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004168 //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 +01004169 }
4170 }
4171 return 0;
4172 }
4173 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004174 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004175 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004176 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 +01004177 write(1, trash, len);
4178 }
4179 return 0;
4180 }
4181 return 0;
4182}
4183
4184
4185/*
4186 * manages the server FSM and its socket. It returns 1 if a state has changed
4187 * (and a resync may be needed), 0 else.
4188 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004189int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004190 int s = t->srv_state;
4191 int c = t->cli_state;
4192 struct buffer *req = t->req;
4193 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004194 appsess *asession_temp = NULL;
4195 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004196 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004197
willy tarreau750a4722005-12-17 13:21:24 +01004198#ifdef DEBUG_FULL
4199 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4200#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004201 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4202 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4203 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4204 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004205 if (s == SV_STIDLE) {
4206 if (c == CL_STHEADERS)
4207 return 0; /* stay in idle, waiting for data to reach the client side */
4208 else if (c == CL_STCLOSE ||
4209 c == CL_STSHUTW ||
4210 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4211 tv_eternity(&t->cnexpire);
4212 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004213 if (!(t->flags & SN_ERR_MASK))
4214 t->flags |= SN_ERR_CLICL;
4215 if (!(t->flags & SN_FINST_MASK))
4216 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004217 return 1;
4218 }
4219 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01004220 /* initiate a connection to the server */
4221 conn_err = connect_server(t);
4222 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004223 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4224 t->srv_state = SV_STCONN;
4225 }
4226 else { /* try again */
4227 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004228 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004229 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004230 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004231 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4232 t->flags &= ~SN_CK_MASK;
4233 t->flags |= SN_CK_DOWN;
4234 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004235 }
4236
willy tarreaub1285d52005-12-18 01:20:14 +01004237 conn_err = connect_server(t);
4238 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004239 t->srv_state = SV_STCONN;
4240 break;
4241 }
4242 }
4243 if (t->conn_retries < 0) {
4244 /* if conn_retries < 0 or other error, let's abort */
4245 tv_eternity(&t->cnexpire);
4246 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004247 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004248 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004249 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004250 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004251 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004252 if (!(t->flags & SN_FINST_MASK))
4253 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004254 }
4255 }
4256 return 1;
4257 }
4258 }
4259 else if (s == SV_STCONN) { /* connection in progress */
4260 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004261 //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 +01004262 return 0; /* nothing changed */
4263 }
4264 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4265 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4266 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004267 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004268 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02004269 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004270 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004271 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004272 if (t->conn_retries >= 0) {
4273 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004274 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004275 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004276 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4277 t->flags &= ~SN_CK_MASK;
4278 t->flags |= SN_CK_DOWN;
4279 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004280 }
willy tarreaub1285d52005-12-18 01:20:14 +01004281 conn_err = connect_server(t);
4282 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004283 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004284 }
willy tarreaub1285d52005-12-18 01:20:14 +01004285 else if (t->res_sw == RES_SILENT)
4286 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4287 else
4288 conn_err = SN_ERR_SRVCL; // it was a connect error.
4289
willy tarreau0f7af912005-12-17 12:21:26 +01004290 /* if conn_retries < 0 or other error, let's abort */
4291 tv_eternity(&t->cnexpire);
4292 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004293 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004294 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004295 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004296 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004297 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004298 if (!(t->flags & SN_FINST_MASK))
4299 t->flags |= SN_FINST_C;
willy tarreaucfbb2182006-04-07 17:37:55 +02004300 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01004301 return 1;
4302 }
4303 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004304 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004305
willy tarreau0f7af912005-12-17 12:21:26 +01004306 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004307 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004308 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004309 tv_eternity(&t->swexpire);
4310 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004311 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004312 if (t->proxy->srvtimeout) {
4313 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4314 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4315 t->srexpire = t->swexpire;
4316 }
4317 else
4318 tv_eternity(&t->swexpire);
4319 }
willy tarreau0f7af912005-12-17 12:21:26 +01004320
4321 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4322 FD_SET(t->srv_fd, StaticReadEvent);
4323 if (t->proxy->srvtimeout)
4324 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4325 else
4326 tv_eternity(&t->srexpire);
4327
4328 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004329 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004330
4331 /* if the user wants to log as soon as possible, without counting
4332 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004333 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004334 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4335 sess_log(t);
4336 }
willy tarreau0f7af912005-12-17 12:21:26 +01004337 }
willy tarreauef900ab2005-12-17 12:52:52 +01004338 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004339 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004340 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4341 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004342 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004343 return 1;
4344 }
4345 }
4346 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004347 /* now parse the partial (or complete) headers */
4348 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4349 char *ptr;
4350 int delete_header;
4351
4352 ptr = rep->lr;
4353
4354 /* look for the end of the current header */
4355 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4356 ptr++;
4357
4358 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004359 int line, len;
4360
4361 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004362
4363 /* first, we'll block if security checks have caught nasty things */
4364 if (t->flags & SN_CACHEABLE) {
4365 if ((t->flags & SN_CACHE_COOK) &&
4366 (t->flags & SN_SCK_ANY) &&
4367 (t->proxy->options & PR_O_CHK_CACHE)) {
4368
4369 /* we're in presence of a cacheable response containing
4370 * a set-cookie header. We'll block it as requested by
4371 * the 'checkcache' option, and send an alert.
4372 */
4373 tv_eternity(&t->srexpire);
4374 tv_eternity(&t->swexpire);
4375 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02004376 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01004377 t->srv_state = SV_STCLOSE;
4378 t->logs.status = 502;
4379 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4380 if (!(t->flags & SN_ERR_MASK))
4381 t->flags |= SN_ERR_PRXCOND;
4382 if (!(t->flags & SN_FINST_MASK))
4383 t->flags |= SN_FINST_H;
4384
4385 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4386 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4387
willy tarreaucfbb2182006-04-07 17:37:55 +02004388 /* TODO : check if there are pending connections on this server */
willy tarreau97f58572005-12-18 00:53:44 +01004389 return 1;
4390 }
4391 }
4392
willy tarreau982249e2005-12-18 00:57:06 +01004393 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4394 if (t->flags & SN_SVDENY) {
4395 tv_eternity(&t->srexpire);
4396 tv_eternity(&t->swexpire);
4397 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02004398 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01004399 t->srv_state = SV_STCLOSE;
4400 t->logs.status = 502;
4401 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4402 if (!(t->flags & SN_ERR_MASK))
4403 t->flags |= SN_ERR_PRXCOND;
4404 if (!(t->flags & SN_FINST_MASK))
4405 t->flags |= SN_FINST_H;
willy tarreaucfbb2182006-04-07 17:37:55 +02004406 /* TODO : check if there are pending connections on this server */
willy tarreau982249e2005-12-18 00:57:06 +01004407 return 1;
4408 }
4409
willy tarreau5cbea6f2005-12-17 12:48:26 +01004410 /* we'll have something else to do here : add new headers ... */
4411
willy tarreaucd878942005-12-17 13:27:43 +01004412 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4413 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004414 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004415 * insert a set-cookie here, except if we want to insert only on POST
4416 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004417 */
willy tarreau750a4722005-12-17 13:21:24 +01004418 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004419 t->proxy->cookie_name,
4420 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004421
willy tarreau036e1ce2005-12-17 13:46:33 +01004422 t->flags |= SN_SCK_INSERTED;
4423
willy tarreau750a4722005-12-17 13:21:24 +01004424 /* Here, we will tell an eventual cache on the client side that we don't
4425 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4426 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4427 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4428 */
willy tarreau240afa62005-12-17 13:14:35 +01004429 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004430 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4431 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004432
4433 if (rep->data + rep->l < rep->h)
4434 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4435 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004436 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004437 }
4438
4439 /* headers to be added */
4440 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004441 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4442 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004443 }
4444
willy tarreau25c4ea52005-12-18 00:49:49 +01004445 /* add a "connection: close" line if needed */
4446 if (t->proxy->options & PR_O_HTTP_CLOSE)
4447 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4448
willy tarreau5cbea6f2005-12-17 12:48:26 +01004449 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004450 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004451 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004452
Willy TARREAU767ba712006-03-01 22:40:50 +01004453 /* client connection already closed or option 'httpclose' required :
4454 * we close the server's outgoing connection right now.
4455 */
4456 if ((req->l == 0) &&
4457 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4458 FD_CLR(t->srv_fd, StaticWriteEvent);
4459 tv_eternity(&t->swexpire);
4460
4461 /* We must ensure that the read part is still alive when switching
4462 * to shutw */
4463 FD_SET(t->srv_fd, StaticReadEvent);
4464 if (t->proxy->srvtimeout)
4465 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4466
4467 shutdown(t->srv_fd, SHUT_WR);
4468 t->srv_state = SV_STSHUTW;
4469 }
4470
willy tarreau25c4ea52005-12-18 00:49:49 +01004471 /* if the user wants to log as soon as possible, without counting
4472 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004473 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004474 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4475 t->logs.bytes = rep->h - rep->data;
4476 sess_log(t);
4477 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004478 break;
4479 }
4480
4481 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4482 if (ptr > rep->r - 2) {
4483 /* this is a partial header, let's wait for more to come */
4484 rep->lr = ptr;
4485 break;
4486 }
4487
4488 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4489 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4490
4491 /* now we know that *ptr is either \r or \n,
4492 * and that there are at least 1 char after it.
4493 */
4494 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4495 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4496 else
4497 rep->lr = ptr + 2; /* \r\n or \n\r */
4498
4499 /*
4500 * now we know that we have a full header ; we can do whatever
4501 * we want with these pointers :
4502 * rep->h = beginning of header
4503 * ptr = end of header (first \r or \n)
4504 * rep->lr = beginning of next line (next rep->h)
4505 * rep->r = end of data (not used at this stage)
4506 */
4507
willy tarreaua1598082005-12-17 13:08:06 +01004508
willy tarreau982249e2005-12-18 00:57:06 +01004509 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004510 t->logs.logwait &= ~LW_RESP;
4511 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004512 switch (t->logs.status) {
4513 case 200:
4514 case 203:
4515 case 206:
4516 case 300:
4517 case 301:
4518 case 410:
4519 /* RFC2616 @13.4:
4520 * "A response received with a status code of
4521 * 200, 203, 206, 300, 301 or 410 MAY be stored
4522 * by a cache (...) unless a cache-control
4523 * directive prohibits caching."
4524 *
4525 * RFC2616 @9.5: POST method :
4526 * "Responses to this method are not cacheable,
4527 * unless the response includes appropriate
4528 * Cache-Control or Expires header fields."
4529 */
4530 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4531 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4532 break;
4533 default:
4534 break;
4535 }
willy tarreau4302f492005-12-18 01:00:37 +01004536 }
4537 else if (t->logs.logwait & LW_RSPHDR) {
4538 struct cap_hdr *h;
4539 int len;
4540 for (h = t->proxy->rsp_cap; h; h = h->next) {
4541 if ((h->namelen + 2 <= ptr - rep->h) &&
4542 (rep->h[h->namelen] == ':') &&
4543 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4544
4545 if (t->rsp_cap[h->index] == NULL)
4546 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4547
4548 len = ptr - (rep->h + h->namelen + 2);
4549 if (len > h->len)
4550 len = h->len;
4551
4552 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4553 t->rsp_cap[h->index][len]=0;
4554 }
4555 }
4556
willy tarreaua1598082005-12-17 13:08:06 +01004557 }
4558
willy tarreau5cbea6f2005-12-17 12:48:26 +01004559 delete_header = 0;
4560
willy tarreau982249e2005-12-18 00:57:06 +01004561 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004562 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004563 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 +01004564 max = ptr - rep->h;
4565 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004566 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004567 trash[len++] = '\n';
4568 write(1, trash, len);
4569 }
4570
willy tarreau25c4ea52005-12-18 00:49:49 +01004571 /* remove "connection: " if needed */
4572 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4573 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4574 delete_header = 1;
4575 }
4576
willy tarreau5cbea6f2005-12-17 12:48:26 +01004577 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004578 if (!delete_header && t->proxy->rsp_exp != NULL
4579 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004580 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004581 char term;
4582
4583 term = *ptr;
4584 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004585 exp = t->proxy->rsp_exp;
4586 do {
4587 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4588 switch (exp->action) {
4589 case ACT_ALLOW:
4590 if (!(t->flags & SN_SVDENY))
4591 t->flags |= SN_SVALLOW;
4592 break;
4593 case ACT_REPLACE:
4594 if (!(t->flags & SN_SVDENY)) {
4595 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4596 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4597 }
4598 break;
4599 case ACT_REMOVE:
4600 if (!(t->flags & SN_SVDENY))
4601 delete_header = 1;
4602 break;
4603 case ACT_DENY:
4604 if (!(t->flags & SN_SVALLOW))
4605 t->flags |= SN_SVDENY;
4606 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004607 case ACT_PASS: /* we simply don't deny this one */
4608 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004609 }
4610 break;
4611 }
willy tarreaue39cd132005-12-17 13:00:18 +01004612 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004613 *ptr = term; /* restore the string terminator */
4614 }
4615
willy tarreau97f58572005-12-18 00:53:44 +01004616 /* check for cache-control: or pragma: headers */
4617 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4618 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4619 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4620 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4621 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004622 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004623 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4624 else {
4625 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004626 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004627 t->flags &= ~SN_CACHE_COOK;
4628 }
4629 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004630 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004631 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004632 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004633 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4634 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004635 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004636 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004637 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4638 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4639 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4640 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4641 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4642 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004643 }
4644 }
4645 }
4646
willy tarreau5cbea6f2005-12-17 12:48:26 +01004647 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004648 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004649 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004650 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004651 char *p1, *p2, *p3, *p4;
4652
willy tarreau97f58572005-12-18 00:53:44 +01004653 t->flags |= SN_SCK_ANY;
4654
willy tarreau5cbea6f2005-12-17 12:48:26 +01004655 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4656
4657 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004658 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004659 p1++;
4660
4661 if (p1 == ptr || *p1 == ';') /* end of cookie */
4662 break;
4663
4664 /* p1 is at the beginning of the cookie name */
4665 p2 = p1;
4666
4667 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4668 p2++;
4669
4670 if (p2 == ptr || *p2 == ';') /* next cookie */
4671 break;
4672
4673 p3 = p2 + 1; /* skips the '=' sign */
4674 if (p3 == ptr)
4675 break;
4676
4677 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004678 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004679 p4++;
4680
4681 /* here, we have the cookie name between p1 and p2,
4682 * and its value between p3 and p4.
4683 * we can process it.
4684 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004685
4686 /* first, let's see if we want to capture it */
4687 if (t->proxy->capture_name != NULL &&
4688 t->logs.srv_cookie == NULL &&
4689 (p4 - p1 >= t->proxy->capture_namelen) &&
4690 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4691 int log_len = p4 - p1;
4692
4693 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4694 Alert("HTTP logging : out of memory.\n");
4695 }
4696
4697 if (log_len > t->proxy->capture_len)
4698 log_len = t->proxy->capture_len;
4699 memcpy(t->logs.srv_cookie, p1, log_len);
4700 t->logs.srv_cookie[log_len] = 0;
4701 }
4702
4703 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4704 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004705 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004706 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004707
4708 /* If the cookie is in insert mode on a known server, we'll delete
4709 * this occurrence because we'll insert another one later.
4710 * We'll delete it too if the "indirect" option is set and we're in
4711 * a direct access. */
4712 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004713 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004714 /* this header must be deleted */
4715 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004716 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004717 }
4718 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4719 /* replace bytes p3->p4 with the cookie name associated
4720 * with this server since we know it.
4721 */
4722 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004723 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004724 }
willy tarreau0174f312005-12-18 01:02:42 +01004725 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4726 /* insert the cookie name associated with this server
4727 * before existing cookie, and insert a delimitor between them..
4728 */
4729 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4730 p3[t->srv->cklen] = COOKIE_DELIM;
4731 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4732 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004733 break;
4734 }
willy tarreau12350152005-12-18 01:03:27 +01004735
4736 /* first, let's see if the cookie is our appcookie*/
4737 if ((t->proxy->appsession_name != NULL) &&
4738 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4739
4740 /* Cool... it's the right one */
4741
willy tarreaub952e1d2005-12-18 01:31:20 +01004742 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004743 asession_temp = &local_asession;
4744
willy tarreaub952e1d2005-12-18 01:31:20 +01004745 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004746 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4747 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4748 }
4749 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4750 asession_temp->sessid[t->proxy->appsession_len] = 0;
4751 asession_temp->serverid = NULL;
4752
4753 /* only do insert, if lookup fails */
4754 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4755 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4756 Alert("Not enought Memory process_srv():asession:calloc().\n");
4757 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4758 return 0;
4759 }
4760 asession_temp->sessid = local_asession.sessid;
4761 asession_temp->serverid = local_asession.serverid;
4762 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004763 }/* end if (chtbl_lookup()) */
4764 else {
willy tarreau12350152005-12-18 01:03:27 +01004765 /* free wasted memory */
4766 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004767 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004768
willy tarreaub952e1d2005-12-18 01:31:20 +01004769 if (asession_temp->serverid == NULL) {
4770 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004771 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4772 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4773 }
4774 asession_temp->serverid[0] = '\0';
4775 }
4776
willy tarreaub952e1d2005-12-18 01:31:20 +01004777 if (asession_temp->serverid[0] == '\0')
4778 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004779
4780 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4781
4782#if defined(DEBUG_HASH)
4783 print_table(&(t->proxy->htbl_proxy));
4784#endif
4785 break;
4786 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004787 else {
4788 // fprintf(stderr,"Ignoring unknown cookie : ");
4789 // write(2, p1, p2-p1);
4790 // fprintf(stderr," = ");
4791 // write(2, p3, p4-p3);
4792 // fprintf(stderr,"\n");
4793 }
4794 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4795 } /* we're now at the end of the cookie value */
4796 } /* end of cookie processing */
4797
willy tarreau97f58572005-12-18 00:53:44 +01004798 /* check for any set-cookie in case we check for cacheability */
4799 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4800 (t->proxy->options & PR_O_CHK_CACHE) &&
4801 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4802 t->flags |= SN_SCK_ANY;
4803 }
4804
willy tarreau5cbea6f2005-12-17 12:48:26 +01004805 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004806 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004807 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004808
willy tarreau5cbea6f2005-12-17 12:48:26 +01004809 rep->h = rep->lr;
4810 } /* while (rep->lr < rep->r) */
4811
4812 /* end of header processing (even if incomplete) */
4813
willy tarreauef900ab2005-12-17 12:52:52 +01004814 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4815 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4816 * full. We cannot loop here since event_srv_read will disable it only if
4817 * rep->l == rlim-data
4818 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004819 FD_SET(t->srv_fd, StaticReadEvent);
4820 if (t->proxy->srvtimeout)
4821 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4822 else
4823 tv_eternity(&t->srexpire);
4824 }
willy tarreau0f7af912005-12-17 12:21:26 +01004825
willy tarreau8337c6b2005-12-17 13:41:01 +01004826 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004827 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004828 tv_eternity(&t->srexpire);
4829 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004830 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02004831 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01004832 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004833 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004834 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004835 if (!(t->flags & SN_ERR_MASK))
4836 t->flags |= SN_ERR_SRVCL;
4837 if (!(t->flags & SN_FINST_MASK))
4838 t->flags |= SN_FINST_H;
willy tarreaucfbb2182006-04-07 17:37:55 +02004839 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01004840 return 1;
4841 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004842 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004843 * since we are in header mode, if there's no space left for headers, we
4844 * won't be able to free more later, so the session will never terminate.
4845 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004846 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 +01004847 FD_CLR(t->srv_fd, StaticReadEvent);
4848 tv_eternity(&t->srexpire);
4849 shutdown(t->srv_fd, SHUT_RD);
4850 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004851 //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 +01004852 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004853 }
4854 /* read timeout : return a 504 to the client.
4855 */
4856 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4857 tv_eternity(&t->srexpire);
4858 tv_eternity(&t->swexpire);
4859 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02004860 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01004861 t->srv_state = SV_STCLOSE;
4862 t->logs.status = 504;
4863 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004864 if (!(t->flags & SN_ERR_MASK))
4865 t->flags |= SN_ERR_SRVTO;
4866 if (!(t->flags & SN_FINST_MASK))
4867 t->flags |= SN_FINST_H;
willy tarreaucfbb2182006-04-07 17:37:55 +02004868 /* TODO : check if there are pending connections on this server */
willy tarreau8337c6b2005-12-17 13:41:01 +01004869 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004870 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004871 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004872 /* FIXME!!! here, we don't want to switch to SHUTW if the
4873 * client shuts read too early, because we may still have
4874 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004875 * The side-effect is that if the client completely closes its
4876 * connection during SV_STHEADER, the connection to the server
4877 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004878 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004879 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004880 FD_CLR(t->srv_fd, StaticWriteEvent);
4881 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004882
4883 /* We must ensure that the read part is still alive when switching
4884 * to shutw */
4885 FD_SET(t->srv_fd, StaticReadEvent);
4886 if (t->proxy->srvtimeout)
4887 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4888
willy tarreau0f7af912005-12-17 12:21:26 +01004889 shutdown(t->srv_fd, SHUT_WR);
4890 t->srv_state = SV_STSHUTW;
4891 return 1;
4892 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004893 /* write timeout */
4894 /* FIXME!!! here, we don't want to switch to SHUTW if the
4895 * client shuts read too early, because we may still have
4896 * some work to do on the headers.
4897 */
4898 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4899 FD_CLR(t->srv_fd, StaticWriteEvent);
4900 tv_eternity(&t->swexpire);
4901 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004902 /* We must ensure that the read part is still alive when switching
4903 * to shutw */
4904 FD_SET(t->srv_fd, StaticReadEvent);
4905 if (t->proxy->srvtimeout)
4906 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4907
4908 /* We must ensure that the read part is still alive when switching
4909 * to shutw */
4910 FD_SET(t->srv_fd, StaticReadEvent);
4911 if (t->proxy->srvtimeout)
4912 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4913
willy tarreau036e1ce2005-12-17 13:46:33 +01004914 t->srv_state = SV_STSHUTW;
4915 if (!(t->flags & SN_ERR_MASK))
4916 t->flags |= SN_ERR_SRVTO;
4917 if (!(t->flags & SN_FINST_MASK))
4918 t->flags |= SN_FINST_H;
4919 return 1;
4920 }
willy tarreau0f7af912005-12-17 12:21:26 +01004921
4922 if (req->l == 0) {
4923 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4924 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4925 tv_eternity(&t->swexpire);
4926 }
4927 }
4928 else { /* client buffer not empty */
4929 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4930 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004931 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004932 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004933 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4934 t->srexpire = t->swexpire;
4935 }
willy tarreau0f7af912005-12-17 12:21:26 +01004936 else
4937 tv_eternity(&t->swexpire);
4938 }
4939 }
4940
willy tarreau5cbea6f2005-12-17 12:48:26 +01004941 /* be nice with the client side which would like to send a complete header
4942 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4943 * would read all remaining data at once ! The client should not write past rep->lr
4944 * when the server is in header state.
4945 */
4946 //return header_processed;
4947 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004948 }
4949 else if (s == SV_STDATA) {
4950 /* read or write error */
4951 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004952 tv_eternity(&t->srexpire);
4953 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004954 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02004955 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01004956 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004957 if (!(t->flags & SN_ERR_MASK))
4958 t->flags |= SN_ERR_SRVCL;
4959 if (!(t->flags & SN_FINST_MASK))
4960 t->flags |= SN_FINST_D;
willy tarreaucfbb2182006-04-07 17:37:55 +02004961 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01004962 return 1;
4963 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004964 /* last read, or end of client write */
4965 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004966 FD_CLR(t->srv_fd, StaticReadEvent);
4967 tv_eternity(&t->srexpire);
4968 shutdown(t->srv_fd, SHUT_RD);
4969 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004970 //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 +01004971 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004972 }
4973 /* end of client read and no more data to send */
4974 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4975 FD_CLR(t->srv_fd, StaticWriteEvent);
4976 tv_eternity(&t->swexpire);
4977 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004978 /* We must ensure that the read part is still alive when switching
4979 * to shutw */
4980 FD_SET(t->srv_fd, StaticReadEvent);
4981 if (t->proxy->srvtimeout)
4982 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4983
willy tarreaua41a8b42005-12-17 14:02:24 +01004984 t->srv_state = SV_STSHUTW;
4985 return 1;
4986 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004987 /* read timeout */
4988 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4989 FD_CLR(t->srv_fd, StaticReadEvent);
4990 tv_eternity(&t->srexpire);
4991 shutdown(t->srv_fd, SHUT_RD);
4992 t->srv_state = SV_STSHUTR;
4993 if (!(t->flags & SN_ERR_MASK))
4994 t->flags |= SN_ERR_SRVTO;
4995 if (!(t->flags & SN_FINST_MASK))
4996 t->flags |= SN_FINST_D;
4997 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004998 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004999 /* write timeout */
5000 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005001 FD_CLR(t->srv_fd, StaticWriteEvent);
5002 tv_eternity(&t->swexpire);
5003 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005004 /* We must ensure that the read part is still alive when switching
5005 * to shutw */
5006 FD_SET(t->srv_fd, StaticReadEvent);
5007 if (t->proxy->srvtimeout)
5008 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005009 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01005010 if (!(t->flags & SN_ERR_MASK))
5011 t->flags |= SN_ERR_SRVTO;
5012 if (!(t->flags & SN_FINST_MASK))
5013 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005014 return 1;
5015 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005016
5017 /* recompute request time-outs */
5018 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005019 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5020 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5021 tv_eternity(&t->swexpire);
5022 }
5023 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005024 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01005025 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5026 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005027 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005028 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005029 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5030 t->srexpire = t->swexpire;
5031 }
willy tarreau0f7af912005-12-17 12:21:26 +01005032 else
5033 tv_eternity(&t->swexpire);
5034 }
5035 }
5036
willy tarreaub1ff9db2005-12-17 13:51:03 +01005037 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01005038 if (rep->l == BUFSIZE) { /* no room to read more data */
5039 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5040 FD_CLR(t->srv_fd, StaticReadEvent);
5041 tv_eternity(&t->srexpire);
5042 }
5043 }
5044 else {
5045 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5046 FD_SET(t->srv_fd, StaticReadEvent);
5047 if (t->proxy->srvtimeout)
5048 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5049 else
5050 tv_eternity(&t->srexpire);
5051 }
5052 }
5053
5054 return 0; /* other cases change nothing */
5055 }
5056 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005057 if (t->res_sw == RES_ERROR) {
5058 //FD_CLR(t->srv_fd, StaticWriteEvent);
5059 tv_eternity(&t->swexpire);
5060 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005061 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005062 //close(t->srv_fd);
5063 t->srv_state = SV_STCLOSE;
5064 if (!(t->flags & SN_ERR_MASK))
5065 t->flags |= SN_ERR_SRVCL;
5066 if (!(t->flags & SN_FINST_MASK))
5067 t->flags |= SN_FINST_D;
willy tarreaucfbb2182006-04-07 17:37:55 +02005068 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005069 return 1;
5070 }
5071 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005072 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005073 tv_eternity(&t->swexpire);
5074 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005075 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005076 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005077 t->srv_state = SV_STCLOSE;
willy tarreaucfbb2182006-04-07 17:37:55 +02005078 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01005079 return 1;
5080 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005081 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5082 //FD_CLR(t->srv_fd, StaticWriteEvent);
5083 tv_eternity(&t->swexpire);
5084 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005085 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005086 //close(t->srv_fd);
5087 t->srv_state = SV_STCLOSE;
5088 if (!(t->flags & SN_ERR_MASK))
5089 t->flags |= SN_ERR_SRVTO;
5090 if (!(t->flags & SN_FINST_MASK))
5091 t->flags |= SN_FINST_D;
willy tarreaucfbb2182006-04-07 17:37:55 +02005092 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005093 return 1;
5094 }
willy tarreau0f7af912005-12-17 12:21:26 +01005095 else if (req->l == 0) {
5096 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5097 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5098 tv_eternity(&t->swexpire);
5099 }
5100 }
5101 else { /* buffer not empty */
5102 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5103 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005104 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005105 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005106 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5107 t->srexpire = t->swexpire;
5108 }
willy tarreau0f7af912005-12-17 12:21:26 +01005109 else
5110 tv_eternity(&t->swexpire);
5111 }
5112 }
5113 return 0;
5114 }
5115 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005116 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005117 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005118 tv_eternity(&t->srexpire);
5119 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005120 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005121 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005122 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005123 if (!(t->flags & SN_ERR_MASK))
5124 t->flags |= SN_ERR_SRVCL;
5125 if (!(t->flags & SN_FINST_MASK))
5126 t->flags |= SN_FINST_D;
willy tarreaucfbb2182006-04-07 17:37:55 +02005127 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01005128 return 1;
5129 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005130 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5131 //FD_CLR(t->srv_fd, StaticReadEvent);
5132 tv_eternity(&t->srexpire);
5133 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005134 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005135 //close(t->srv_fd);
5136 t->srv_state = SV_STCLOSE;
willy tarreaucfbb2182006-04-07 17:37:55 +02005137 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005138 return 1;
5139 }
5140 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5141 //FD_CLR(t->srv_fd, StaticReadEvent);
5142 tv_eternity(&t->srexpire);
5143 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005144 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005145 //close(t->srv_fd);
5146 t->srv_state = SV_STCLOSE;
5147 if (!(t->flags & SN_ERR_MASK))
5148 t->flags |= SN_ERR_SRVTO;
5149 if (!(t->flags & SN_FINST_MASK))
5150 t->flags |= SN_FINST_D;
willy tarreaucfbb2182006-04-07 17:37:55 +02005151 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005152 return 1;
5153 }
willy tarreau0f7af912005-12-17 12:21:26 +01005154 else if (rep->l == BUFSIZE) { /* no room to read more data */
5155 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5156 FD_CLR(t->srv_fd, StaticReadEvent);
5157 tv_eternity(&t->srexpire);
5158 }
5159 }
5160 else {
5161 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5162 FD_SET(t->srv_fd, StaticReadEvent);
5163 if (t->proxy->srvtimeout)
5164 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5165 else
5166 tv_eternity(&t->srexpire);
5167 }
5168 }
5169 return 0;
5170 }
5171 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005172 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005173 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005174 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 +01005175 write(1, trash, len);
5176 }
5177 return 0;
5178 }
5179 return 0;
5180}
5181
5182
willy tarreau5cbea6f2005-12-17 12:48:26 +01005183/* Processes the client and server jobs of a session task, then
5184 * puts it back to the wait queue in a clean state, or
5185 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005186 * the time the task accepts to wait, or TIME_ETERNITY for
5187 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005188 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005189int process_session(struct task *t) {
5190 struct session *s = t->context;
5191 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005192
willy tarreau5cbea6f2005-12-17 12:48:26 +01005193 do {
5194 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005195 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005196 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005197 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005198 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005199 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005200 } while (fsm_resync);
5201
5202 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005203 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005204 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005205
willy tarreau5cbea6f2005-12-17 12:48:26 +01005206 tv_min(&min1, &s->crexpire, &s->cwexpire);
5207 tv_min(&min2, &s->srexpire, &s->swexpire);
5208 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005209 tv_min(&t->expire, &min1, &min2);
5210
5211 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005212 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005213
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005214#ifdef DEBUG_FULL
5215 /* DEBUG code : this should never ever happen, otherwise it indicates
5216 * that a task still has something to do and will provoke a quick loop.
5217 */
5218 if (tv_remain2(&now, &t->expire) <= 0)
5219 exit(100);
5220#endif
5221
willy tarreaub952e1d2005-12-18 01:31:20 +01005222 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005223 }
5224
willy tarreau5cbea6f2005-12-17 12:48:26 +01005225 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005226 actconn--;
5227
willy tarreau982249e2005-12-18 00:57:06 +01005228 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005229 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005230 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 +01005231 write(1, trash, len);
5232 }
5233
willy tarreau750a4722005-12-17 13:21:24 +01005234 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005235 if (s->rep != NULL)
5236 s->logs.bytes = s->rep->total;
5237
willy tarreau9fe663a2005-12-17 13:02:59 +01005238 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005239 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005240 sess_log(s);
5241
willy tarreau0f7af912005-12-17 12:21:26 +01005242 /* the task MUST not be in the run queue anymore */
5243 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005244 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005245 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005246 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005247}
5248
5249
5250
5251/*
5252 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005253 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005254 */
5255int process_chk(struct task *t) {
5256 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005257 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005258 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005259
willy tarreauef900ab2005-12-17 12:52:52 +01005260 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005261
willy tarreau25424f82006-03-19 19:37:48 +01005262 new_chk:
5263 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005264 if (fd < 0) { /* no check currently running */
5265 //fprintf(stderr, "process_chk: 2\n");
5266 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5267 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005268 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005269 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005270
5271 /* we don't send any health-checks when the proxy is stopped or when
5272 * the server should not be checked.
5273 */
5274 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005275 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5276 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005277 task_queue(t); /* restore t to its place in the task list */
5278 return tv_remain2(&now, &t->expire);
5279 }
5280
willy tarreau5cbea6f2005-12-17 12:48:26 +01005281 /* we'll initiate a new check */
5282 s->result = 0; /* no result yet */
5283 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005284 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005285 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5286 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5287 //fprintf(stderr, "process_chk: 3\n");
5288
willy tarreaua41a8b42005-12-17 14:02:24 +01005289 /* we'll connect to the check port on the server */
5290 sa = s->addr;
5291 sa.sin_port = htons(s->check_port);
5292
willy tarreau0174f312005-12-18 01:02:42 +01005293 /* allow specific binding :
5294 * - server-specific at first
5295 * - proxy-specific next
5296 */
5297 if (s->state & SRV_BIND_SRC) {
5298 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5299 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5300 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5301 s->proxy->id, s->id);
5302 s->result = -1;
5303 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005304 }
willy tarreau0174f312005-12-18 01:02:42 +01005305 else if (s->proxy->options & PR_O_BIND_SRC) {
5306 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5307 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5308 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5309 s->proxy->id);
5310 s->result = -1;
5311 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005312 }
willy tarreau0174f312005-12-18 01:02:42 +01005313
5314 if (!s->result) {
5315 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5316 /* OK, connection in progress or established */
5317
5318 //fprintf(stderr, "process_chk: 4\n");
5319
5320 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5321 fdtab[fd].owner = t;
5322 fdtab[fd].read = &event_srv_chk_r;
5323 fdtab[fd].write = &event_srv_chk_w;
5324 fdtab[fd].state = FD_STCONN; /* connection in progress */
5325 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005326#ifdef DEBUG_FULL
5327 assert (!FD_ISSET(fd, StaticReadEvent));
5328#endif
willy tarreau0174f312005-12-18 01:02:42 +01005329 fd_insert(fd);
5330 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5331 tv_delayfrom(&t->expire, &now, s->inter);
5332 task_queue(t); /* restore t to its place in the task list */
5333 return tv_remain(&now, &t->expire);
5334 }
5335 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5336 s->result = -1; /* a real error */
5337 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005338 }
5339 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005340 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005341 }
5342
5343 if (!s->result) { /* nothing done */
5344 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005345 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5346 tv_delayfrom(&t->expire, &t->expire, s->inter);
5347 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005348 }
5349
5350 /* here, we have seen a failure */
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 tarreau535ae7a2005-12-17 12:58:00 +01005355 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005356 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005357 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005358 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." : "");
willy tarreauef900ab2005-12-17 12:52:52 +01005367
willy tarreau62084d42006-03-24 18:57:41 +01005368 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
willy tarreaudd07e972005-12-18 00:48:48 +01005369 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 tarreau5cbea6f2005-12-17 12:48:26 +01005373 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005374 }
5375
5376 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005377 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005378 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5379 tv_delayfrom(&t->expire, &t->expire, s->inter);
5380 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005381 }
5382 else {
5383 //fprintf(stderr, "process_chk: 8\n");
5384 /* there was a test running */
5385 if (s->result > 0) { /* good server detected */
5386 //fprintf(stderr, "process_chk: 9\n");
5387 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005388 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02005389 s->state |= SRV_RUNNING;
5390
willy tarreau535ae7a2005-12-17 12:58:00 +01005391 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005392 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005393 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005394 Warning("%sServer %s/%s UP. %d active and %d backup servers online.%s\n",
5395 s->state & SRV_BACKUP ? "Backup " : "",
5396 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5397 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5398 send_log(s->proxy, LOG_NOTICE,
5399 "%sServer %s/%s is UP. %d active and %d backup servers online.%s\n",
5400 s->state & SRV_BACKUP ? "Backup " : "",
5401 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5402 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreau535ae7a2005-12-17 12:58:00 +01005403 }
willy tarreauef900ab2005-12-17 12:52:52 +01005404
willy tarreaue47c8d72005-12-17 12:55:52 +01005405 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005406 }
willy tarreauef900ab2005-12-17 12:52:52 +01005407 s->curfd = -1; /* no check running anymore */
5408 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005409 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005410 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5411 tv_delayfrom(&t->expire, &t->expire, s->inter);
5412 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005413 }
5414 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5415 //fprintf(stderr, "process_chk: 10\n");
5416 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005417 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005418 s->health--; /* still good */
5419 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005420 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005421
willy tarreau62084d42006-03-24 18:57:41 +01005422 if (s->health == s->rise) {
5423 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005424 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005425 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5426 s->state & SRV_BACKUP ? "Backup " : "",
5427 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5428 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5429 send_log(s->proxy, LOG_ALERT,
5430 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5431 s->state & SRV_BACKUP ? "Backup " : "",
5432 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5433 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5434
5435 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5436 Alert("Proxy %s has no server available !\n", s->proxy->id);
5437 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5438 }
5439 }
willy tarreauef900ab2005-12-17 12:52:52 +01005440
willy tarreau5cbea6f2005-12-17 12:48:26 +01005441 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005442 }
5443 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005444 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005445 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005446 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5447 tv_delayfrom(&t->expire, &t->expire, s->inter);
5448 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005449 }
5450 /* if result is 0 and there's no timeout, we have to wait again */
5451 }
5452 //fprintf(stderr, "process_chk: 11\n");
5453 s->result = 0;
5454 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005455 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005456}
5457
5458
willy tarreau5cbea6f2005-12-17 12:48:26 +01005459
willy tarreau0f7af912005-12-17 12:21:26 +01005460#if STATTIME > 0
5461int stats(void);
5462#endif
5463
5464/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005465 * This does 4 things :
5466 * - wake up all expired tasks
5467 * - call all runnable tasks
5468 * - call maintain_proxies() to enable/disable the listeners
5469 * - return the delay till next event in ms, -1 = wait indefinitely
5470 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5471 *
willy tarreau0f7af912005-12-17 12:21:26 +01005472 */
5473
willy tarreau1c2ad212005-12-18 01:11:29 +01005474int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005475 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005476 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005477 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005478
willy tarreaub952e1d2005-12-18 01:31:20 +01005479 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005480
willy tarreau1c2ad212005-12-18 01:11:29 +01005481 /* look for expired tasks and add them to the run queue.
5482 */
5483 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5484 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5485 tnext = t->next;
5486 if (t->state & TASK_RUNNING)
5487 continue;
5488
willy tarreaub952e1d2005-12-18 01:31:20 +01005489 if (tv_iseternity(&t->expire))
5490 continue;
5491
willy tarreau1c2ad212005-12-18 01:11:29 +01005492 /* wakeup expired entries. It doesn't matter if they are
5493 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005494 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005495 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005496 task_wakeup(&rq, t);
5497 }
5498 else {
5499 /* first non-runnable task. Use its expiration date as an upper bound */
5500 int temp_time = tv_remain(&now, &t->expire);
5501 if (temp_time)
5502 next_time = temp_time;
5503 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005504 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005505 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005506
willy tarreau1c2ad212005-12-18 01:11:29 +01005507 /* process each task in the run queue now. Each task may be deleted
5508 * since we only use tnext.
5509 */
5510 tnext = rq;
5511 while ((t = tnext) != NULL) {
5512 int temp_time;
5513
5514 tnext = t->rqnext;
5515 task_sleep(&rq, t);
5516 temp_time = t->process(t);
5517 next_time = MINTIME(temp_time, next_time);
5518 }
5519
5520 /* maintain all proxies in a consistent state. This should quickly become a task */
5521 time2 = maintain_proxies();
5522 return MINTIME(time2, next_time);
5523}
5524
5525
5526#if defined(ENABLE_EPOLL)
5527
5528/*
5529 * Main epoll() loop.
5530 */
5531
5532/* does 3 actions :
5533 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5534 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5535 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5536 *
5537 * returns 0 if initialization failed, !0 otherwise.
5538 */
5539
5540int epoll_loop(int action) {
5541 int next_time;
5542 int status;
5543 int fd;
5544
5545 int fds, count;
5546 int pr, pw, sr, sw;
5547 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5548 struct epoll_event ev;
5549
5550 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005551 static struct epoll_event *epoll_events = NULL;
5552 static int epoll_fd;
5553
5554 if (action == POLL_LOOP_ACTION_INIT) {
5555 epoll_fd = epoll_create(global.maxsock + 1);
5556 if (epoll_fd < 0)
5557 return 0;
5558 else {
5559 epoll_events = (struct epoll_event*)
5560 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5561 PrevReadEvent = (fd_set *)
5562 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5563 PrevWriteEvent = (fd_set *)
5564 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005565 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005566 return 1;
5567 }
5568 else if (action == POLL_LOOP_ACTION_CLEAN) {
5569 if (PrevWriteEvent) free(PrevWriteEvent);
5570 if (PrevReadEvent) free(PrevReadEvent);
5571 if (epoll_events) free(epoll_events);
5572 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005573 epoll_fd = 0;
5574 return 1;
5575 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005576
willy tarreau1c2ad212005-12-18 01:11:29 +01005577 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005578
willy tarreau1c2ad212005-12-18 01:11:29 +01005579 tv_now(&now);
5580
5581 while (1) {
5582 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005583
5584 /* stop when there's no connection left and we don't allow them anymore */
5585 if (!actconn && listeners == 0)
5586 break;
5587
willy tarreau0f7af912005-12-17 12:21:26 +01005588#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005589 {
5590 int time2;
5591 time2 = stats();
5592 next_time = MINTIME(time2, next_time);
5593 }
willy tarreau0f7af912005-12-17 12:21:26 +01005594#endif
5595
willy tarreau1c2ad212005-12-18 01:11:29 +01005596 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5597
5598 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5599 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5600
5601 if ((ro^rn) | (wo^wn)) {
5602 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5603#define FDSETS_ARE_INT_ALIGNED
5604#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005605
willy tarreauad90a0c2005-12-18 01:09:15 +01005606#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5607#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005608 pr = (ro >> count) & 1;
5609 pw = (wo >> count) & 1;
5610 sr = (rn >> count) & 1;
5611 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005612#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005613 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5614 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5615 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5616 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005617#endif
5618#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005619 pr = FD_ISSET(fd, PrevReadEvent);
5620 pw = FD_ISSET(fd, PrevWriteEvent);
5621 sr = FD_ISSET(fd, StaticReadEvent);
5622 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005623#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005624 if (!((sr^pr) | (sw^pw)))
5625 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005626
willy tarreau1c2ad212005-12-18 01:11:29 +01005627 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5628 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005629
willy tarreaub952e1d2005-12-18 01:31:20 +01005630#ifdef EPOLL_CTL_MOD_WORKAROUND
5631 /* I encountered a rarely reproducible problem with
5632 * EPOLL_CTL_MOD where a modified FD (systematically
5633 * the one in epoll_events[0], fd#7) would sometimes
5634 * be set EPOLL_OUT while asked for a read ! This is
5635 * with the 2.4 epoll patch. The workaround is to
5636 * delete then recreate in case of modification.
5637 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5638 * nor RHEL kernels.
5639 */
5640
5641 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5642 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5643
5644 if ((sr | sw))
5645 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5646#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005647 if ((pr | pw)) {
5648 /* the file-descriptor already exists... */
5649 if ((sr | sw)) {
5650 /* ...and it will still exist */
5651 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5652 // perror("epoll_ctl(MOD)");
5653 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005654 }
5655 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005656 /* ...and it will be removed */
5657 if (fdtab[fd].state != FD_STCLOSE &&
5658 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5659 // perror("epoll_ctl(DEL)");
5660 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005661 }
5662 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005663 } else {
5664 /* the file-descriptor did not exist, let's add it */
5665 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5666 // perror("epoll_ctl(ADD)");
5667 // exit(1);
5668 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005669 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005670#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005671 }
5672 ((int*)PrevReadEvent)[fds] = rn;
5673 ((int*)PrevWriteEvent)[fds] = wn;
5674 }
5675 }
5676
5677 /* now let's wait for events */
5678 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5679 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005680
willy tarreau1c2ad212005-12-18 01:11:29 +01005681 for (count = 0; count < status; count++) {
5682 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01005683
5684 if (FD_ISSET(fd, StaticReadEvent)) {
5685 if (fdtab[fd].state == FD_STCLOSE)
5686 continue;
5687 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5688 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005689 }
willy tarreau05be12b2006-03-19 19:35:00 +01005690
5691 if (FD_ISSET(fd, StaticWriteEvent)) {
5692 if (fdtab[fd].state == FD_STCLOSE)
5693 continue;
5694 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5695 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005696 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005697 }
5698 }
5699 return 1;
5700}
5701#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005702
willy tarreauad90a0c2005-12-18 01:09:15 +01005703
willy tarreau5cbea6f2005-12-17 12:48:26 +01005704
willy tarreau1c2ad212005-12-18 01:11:29 +01005705#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005706
willy tarreau1c2ad212005-12-18 01:11:29 +01005707/*
5708 * Main poll() loop.
5709 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005710
willy tarreau1c2ad212005-12-18 01:11:29 +01005711/* does 3 actions :
5712 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5713 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5714 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5715 *
5716 * returns 0 if initialization failed, !0 otherwise.
5717 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005718
willy tarreau1c2ad212005-12-18 01:11:29 +01005719int poll_loop(int action) {
5720 int next_time;
5721 int status;
5722 int fd, nbfd;
5723
5724 int fds, count;
5725 int sr, sw;
5726 unsigned rn, wn; /* read new, write new */
5727
5728 /* private data */
5729 static struct pollfd *poll_events = NULL;
5730
5731 if (action == POLL_LOOP_ACTION_INIT) {
5732 poll_events = (struct pollfd*)
5733 calloc(1, sizeof(struct pollfd) * global.maxsock);
5734 return 1;
5735 }
5736 else if (action == POLL_LOOP_ACTION_CLEAN) {
5737 if (poll_events)
5738 free(poll_events);
5739 return 1;
5740 }
5741
5742 /* OK, it's POLL_LOOP_ACTION_RUN */
5743
5744 tv_now(&now);
5745
5746 while (1) {
5747 next_time = process_runnable_tasks();
5748
5749 /* stop when there's no connection left and we don't allow them anymore */
5750 if (!actconn && listeners == 0)
5751 break;
5752
5753#if STATTIME > 0
5754 {
5755 int time2;
5756 time2 = stats();
5757 next_time = MINTIME(time2, next_time);
5758 }
5759#endif
5760
5761
5762 nbfd = 0;
5763 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5764
5765 rn = ((int*)StaticReadEvent)[fds];
5766 wn = ((int*)StaticWriteEvent)[fds];
5767
5768 if ((rn|wn)) {
5769 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5770#define FDSETS_ARE_INT_ALIGNED
5771#ifdef FDSETS_ARE_INT_ALIGNED
5772
5773#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5774#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5775 sr = (rn >> count) & 1;
5776 sw = (wn >> count) & 1;
5777#else
5778 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5779 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5780#endif
5781#else
5782 sr = FD_ISSET(fd, StaticReadEvent);
5783 sw = FD_ISSET(fd, StaticWriteEvent);
5784#endif
5785 if ((sr|sw)) {
5786 poll_events[nbfd].fd = fd;
5787 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5788 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005789 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005790 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005791 }
5792 }
5793
5794 /* now let's wait for events */
5795 status = poll(poll_events, nbfd, next_time);
5796 tv_now(&now);
5797
5798 for (count = 0; status > 0 && count < nbfd; count++) {
5799 fd = poll_events[count].fd;
5800
5801 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5802 continue;
5803
5804 /* ok, we found one active fd */
5805 status--;
5806
willy tarreau05be12b2006-03-19 19:35:00 +01005807 if (FD_ISSET(fd, StaticReadEvent)) {
5808 if (fdtab[fd].state == FD_STCLOSE)
5809 continue;
5810 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5811 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005812 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005813
willy tarreau05be12b2006-03-19 19:35:00 +01005814 if (FD_ISSET(fd, StaticWriteEvent)) {
5815 if (fdtab[fd].state == FD_STCLOSE)
5816 continue;
5817 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5818 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005819 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005820 }
5821 }
5822 return 1;
5823}
willy tarreauad90a0c2005-12-18 01:09:15 +01005824#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005825
willy tarreauad90a0c2005-12-18 01:09:15 +01005826
willy tarreauad90a0c2005-12-18 01:09:15 +01005827
willy tarreau1c2ad212005-12-18 01:11:29 +01005828/*
5829 * Main select() loop.
5830 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005831
willy tarreau1c2ad212005-12-18 01:11:29 +01005832/* does 3 actions :
5833 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5834 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5835 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5836 *
5837 * returns 0 if initialization failed, !0 otherwise.
5838 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005839
willy tarreauad90a0c2005-12-18 01:09:15 +01005840
willy tarreau1c2ad212005-12-18 01:11:29 +01005841int select_loop(int action) {
5842 int next_time;
5843 int status;
5844 int fd,i;
5845 struct timeval delta;
5846 int readnotnull, writenotnull;
5847 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005848
willy tarreau1c2ad212005-12-18 01:11:29 +01005849 if (action == POLL_LOOP_ACTION_INIT) {
5850 ReadEvent = (fd_set *)
5851 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5852 WriteEvent = (fd_set *)
5853 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5854 return 1;
5855 }
5856 else if (action == POLL_LOOP_ACTION_CLEAN) {
5857 if (WriteEvent) free(WriteEvent);
5858 if (ReadEvent) free(ReadEvent);
5859 return 1;
5860 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005861
willy tarreau1c2ad212005-12-18 01:11:29 +01005862 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005863
willy tarreau1c2ad212005-12-18 01:11:29 +01005864 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005865
willy tarreau1c2ad212005-12-18 01:11:29 +01005866 while (1) {
5867 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005868
willy tarreau1c2ad212005-12-18 01:11:29 +01005869 /* stop when there's no connection left and we don't allow them anymore */
5870 if (!actconn && listeners == 0)
5871 break;
5872
5873#if STATTIME > 0
5874 {
5875 int time2;
5876 time2 = stats();
5877 next_time = MINTIME(time2, next_time);
5878 }
5879#endif
5880
willy tarreau1c2ad212005-12-18 01:11:29 +01005881 if (next_time > 0) { /* FIXME */
5882 /* Convert to timeval */
5883 /* to avoid eventual select loops due to timer precision */
5884 next_time += SCHEDULER_RESOLUTION;
5885 delta.tv_sec = next_time / 1000;
5886 delta.tv_usec = (next_time % 1000) * 1000;
5887 }
5888 else if (next_time == 0) { /* allow select to return immediately when needed */
5889 delta.tv_sec = delta.tv_usec = 0;
5890 }
5891
5892
5893 /* let's restore fdset state */
5894
5895 readnotnull = 0; writenotnull = 0;
5896 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5897 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5898 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5899 }
5900
5901 // /* just a verification code, needs to be removed for performance */
5902 // for (i=0; i<maxfd; i++) {
5903 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5904 // abort();
5905 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5906 // abort();
5907 //
5908 // }
5909
5910 status = select(maxfd,
5911 readnotnull ? ReadEvent : NULL,
5912 writenotnull ? WriteEvent : NULL,
5913 NULL,
5914 (next_time >= 0) ? &delta : NULL);
5915
5916 /* this is an experiment on the separation of the select work */
5917 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5918 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5919
5920 tv_now(&now);
5921
5922 if (status > 0) { /* must proceed with events */
5923
5924 int fds;
5925 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005926
willy tarreau1c2ad212005-12-18 01:11:29 +01005927 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5928 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5929 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5930
5931 /* if we specify read first, the accepts and zero reads will be
5932 * seen first. Moreover, system buffers will be flushed faster.
5933 */
willy tarreau05be12b2006-03-19 19:35:00 +01005934 if (FD_ISSET(fd, ReadEvent)) {
5935 if (fdtab[fd].state == FD_STCLOSE)
5936 continue;
5937 fdtab[fd].read(fd);
5938 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005939
willy tarreau05be12b2006-03-19 19:35:00 +01005940 if (FD_ISSET(fd, WriteEvent)) {
5941 if (fdtab[fd].state == FD_STCLOSE)
5942 continue;
5943 fdtab[fd].write(fd);
5944 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005945 }
5946 }
5947 else {
5948 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005949 }
willy tarreau0f7af912005-12-17 12:21:26 +01005950 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005951 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005952}
5953
5954
5955#if STATTIME > 0
5956/*
5957 * Display proxy statistics regularly. It is designed to be called from the
5958 * select_loop().
5959 */
5960int stats(void) {
5961 static int lines;
5962 static struct timeval nextevt;
5963 static struct timeval lastevt;
5964 static struct timeval starttime = {0,0};
5965 unsigned long totaltime, deltatime;
5966 int ret;
5967
willy tarreau750a4722005-12-17 13:21:24 +01005968 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005969 deltatime = (tv_diff(&lastevt, &now)?:1);
5970 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005971
willy tarreau9fe663a2005-12-17 13:02:59 +01005972 if (global.mode & MODE_STATS) {
5973 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005974 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005975 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5976 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005977 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005978 actconn, totalconn,
5979 stats_tsk_new, stats_tsk_good,
5980 stats_tsk_left, stats_tsk_right,
5981 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5982 }
5983 }
5984
5985 tv_delayfrom(&nextevt, &now, STATTIME);
5986
5987 lastevt=now;
5988 }
5989 ret = tv_remain(&now, &nextevt);
5990 return ret;
5991}
5992#endif
5993
5994
5995/*
5996 * this function enables proxies when there are enough free sessions,
5997 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005998 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005999 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01006000 */
6001static int maintain_proxies(void) {
6002 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01006003 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006004 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01006005
6006 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01006007 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01006008
6009 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01006010 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01006011 while (p) {
6012 if (p->nbconn < p->maxconn) {
6013 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006014 for (l = p->listen; l != NULL; l = l->next) {
6015 FD_SET(l->fd, StaticReadEvent);
6016 }
willy tarreau0f7af912005-12-17 12:21:26 +01006017 p->state = PR_STRUN;
6018 }
6019 }
6020 else {
6021 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006022 for (l = p->listen; l != NULL; l = l->next) {
6023 FD_CLR(l->fd, StaticReadEvent);
6024 }
willy tarreau0f7af912005-12-17 12:21:26 +01006025 p->state = PR_STIDLE;
6026 }
6027 }
6028 p = p->next;
6029 }
6030 }
6031 else { /* block all proxies */
6032 while (p) {
6033 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006034 for (l = p->listen; l != NULL; l = l->next) {
6035 FD_CLR(l->fd, StaticReadEvent);
6036 }
willy tarreau0f7af912005-12-17 12:21:26 +01006037 p->state = PR_STIDLE;
6038 }
6039 p = p->next;
6040 }
6041 }
6042
willy tarreau5cbea6f2005-12-17 12:48:26 +01006043 if (stopping) {
6044 p = proxy;
6045 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01006046 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006047 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006048 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006049 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006050 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006051 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006052
willy tarreaua41a8b42005-12-17 14:02:24 +01006053 for (l = p->listen; l != NULL; l = l->next) {
6054 fd_delete(l->fd);
6055 listeners--;
6056 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006057 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006058 }
6059 else {
6060 tleft = MINTIME(t, tleft);
6061 }
6062 }
6063 p = p->next;
6064 }
6065 }
6066 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006067}
6068
6069/*
6070 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006071 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6072 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006073 */
6074static void soft_stop(void) {
6075 struct proxy *p;
6076
6077 stopping = 1;
6078 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006079 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006080 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006081 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006082 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006083 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006084 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006085 }
willy tarreau0f7af912005-12-17 12:21:26 +01006086 p = p->next;
6087 }
6088}
6089
willy tarreaudbd3bef2006-01-20 19:35:18 +01006090static void pause_proxy(struct proxy *p) {
6091 struct listener *l;
6092 for (l = p->listen; l != NULL; l = l->next) {
6093 shutdown(l->fd, SHUT_RD);
6094 FD_CLR(l->fd, StaticReadEvent);
6095 p->state = PR_STPAUSED;
6096 }
6097}
6098
6099/*
6100 * This function temporarily disables listening so that another new instance
6101 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006102 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006103 * the proxy, or a SIGTTIN can be sent to listen again.
6104 */
6105static void pause_proxies(void) {
6106 struct proxy *p;
6107
6108 p = proxy;
6109 tv_now(&now); /* else, the old time before select will be used */
6110 while (p) {
6111 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6112 Warning("Pausing proxy %s.\n", p->id);
6113 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6114 pause_proxy(p);
6115 }
6116 p = p->next;
6117 }
6118}
6119
6120
6121/*
6122 * This function reactivates listening. This can be used after a call to
6123 * sig_pause(), for example when a new instance has failed starting up.
6124 * It is designed to be called upon reception of a SIGTTIN.
6125 */
6126static void listen_proxies(void) {
6127 struct proxy *p;
6128 struct listener *l;
6129
6130 p = proxy;
6131 tv_now(&now); /* else, the old time before select will be used */
6132 while (p) {
6133 if (p->state == PR_STPAUSED) {
6134 Warning("Enabling proxy %s.\n", p->id);
6135 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6136
6137 for (l = p->listen; l != NULL; l = l->next) {
6138 if (listen(l->fd, p->maxconn) == 0) {
6139 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6140 FD_SET(l->fd, StaticReadEvent);
6141 p->state = PR_STRUN;
6142 }
6143 else
6144 p->state = PR_STIDLE;
6145 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006146 int port;
6147
6148 if (l->addr.ss_family == AF_INET6)
6149 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6150 else
6151 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6152
willy tarreaudbd3bef2006-01-20 19:35:18 +01006153 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006154 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006155 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006156 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006157 /* Another port might have been enabled. Let's stop everything. */
6158 pause_proxy(p);
6159 break;
6160 }
6161 }
6162 }
6163 p = p->next;
6164 }
6165}
6166
6167
willy tarreau0f7af912005-12-17 12:21:26 +01006168/*
6169 * upon SIGUSR1, let's have a soft stop.
6170 */
6171void sig_soft_stop(int sig) {
6172 soft_stop();
6173 signal(sig, SIG_IGN);
6174}
6175
willy tarreaudbd3bef2006-01-20 19:35:18 +01006176/*
6177 * upon SIGTTOU, we pause everything
6178 */
6179void sig_pause(int sig) {
6180 pause_proxies();
6181 signal(sig, sig_pause);
6182}
willy tarreau0f7af912005-12-17 12:21:26 +01006183
willy tarreau8337c6b2005-12-17 13:41:01 +01006184/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006185 * upon SIGTTIN, let's have a soft stop.
6186 */
6187void sig_listen(int sig) {
6188 listen_proxies();
6189 signal(sig, sig_listen);
6190}
6191
6192/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006193 * this function dumps every server's state when the process receives SIGHUP.
6194 */
6195void sig_dump_state(int sig) {
6196 struct proxy *p = proxy;
6197
6198 Warning("SIGHUP received, dumping servers states.\n");
6199 while (p) {
6200 struct server *s = p->srv;
6201
6202 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
6203 while (s) {
6204 if (s->state & SRV_RUNNING) {
willy tarreaufd6dfe72006-03-19 19:38:19 +01006205 Warning("SIGHUP: Server %s/%s is UP.\n", p->id, s->id);
6206 send_log(p, LOG_NOTICE, "SIGUP: Server %s/%s is UP.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006207 }
6208 else {
willy tarreaufd6dfe72006-03-19 19:38:19 +01006209 Warning("SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
6210 send_log(p, LOG_NOTICE, "SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006211 }
6212 s = s->next;
6213 }
willy tarreaudd07e972005-12-18 00:48:48 +01006214
willy tarreau62084d42006-03-24 18:57:41 +01006215 if (p->srv_act == 0) {
6216 if (p->srv_bck) {
6217 Warning("SIGHUP: Proxy %s is running on backup servers !\n", p->id);
6218 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s is running on backup servers !\n", p->id);
6219 } else {
6220 Warning("SIGHUP: Proxy %s has no server available !\n", p->id);
6221 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s has no server available !\n", p->id);
6222 }
6223 }
willy tarreaudd07e972005-12-18 00:48:48 +01006224
willy tarreau8337c6b2005-12-17 13:41:01 +01006225 p = p->next;
6226 }
6227 signal(sig, sig_dump_state);
6228}
6229
willy tarreau0f7af912005-12-17 12:21:26 +01006230void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006231 struct task *t, *tnext;
6232 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006233
willy tarreau5cbea6f2005-12-17 12:48:26 +01006234 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
6235 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
6236 tnext = t->next;
6237 s = t->context;
6238 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6239 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6240 "req=%d, rep=%d, clifd=%d\n",
6241 s, tv_remain(&now, &t->expire),
6242 s->cli_state,
6243 s->srv_state,
6244 FD_ISSET(s->cli_fd, StaticReadEvent),
6245 FD_ISSET(s->cli_fd, StaticWriteEvent),
6246 FD_ISSET(s->srv_fd, StaticReadEvent),
6247 FD_ISSET(s->srv_fd, StaticWriteEvent),
6248 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6249 );
willy tarreau0f7af912005-12-17 12:21:26 +01006250 }
willy tarreau12350152005-12-18 01:03:27 +01006251}
6252
willy tarreau64a3cc32005-12-18 01:13:11 +01006253#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006254static void fast_stop(void)
6255{
6256 struct proxy *p;
6257 p = proxy;
6258 while (p) {
6259 p->grace = 0;
6260 p = p->next;
6261 }
6262 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006263}
6264
willy tarreau12350152005-12-18 01:03:27 +01006265void sig_int(int sig) {
6266 /* This would normally be a hard stop,
6267 but we want to be sure about deallocation,
6268 and so on, so we do a soft stop with
6269 0 GRACE time
6270 */
6271 fast_stop();
6272 /* If we are killed twice, we decide to die*/
6273 signal(sig, SIG_DFL);
6274}
6275
6276void sig_term(int sig) {
6277 /* This would normally be a hard stop,
6278 but we want to be sure about deallocation,
6279 and so on, so we do a soft stop with
6280 0 GRACE time
6281 */
6282 fast_stop();
6283 /* If we are killed twice, we decide to die*/
6284 signal(sig, SIG_DFL);
6285}
willy tarreau64a3cc32005-12-18 01:13:11 +01006286#endif
willy tarreau12350152005-12-18 01:03:27 +01006287
willy tarreauc1f47532005-12-18 01:08:26 +01006288/* returns the pointer to an error in the replacement string, or NULL if OK */
6289char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006290 struct hdr_exp *exp;
6291
willy tarreauc1f47532005-12-18 01:08:26 +01006292 if (replace != NULL) {
6293 char *err;
6294 err = check_replace_string(replace);
6295 if (err)
6296 return err;
6297 }
6298
willy tarreaue39cd132005-12-17 13:00:18 +01006299 while (*head != NULL)
6300 head = &(*head)->next;
6301
6302 exp = calloc(1, sizeof(struct hdr_exp));
6303
6304 exp->preg = preg;
6305 exp->replace = replace;
6306 exp->action = action;
6307 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006308
6309 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006310}
6311
willy tarreau9fe663a2005-12-17 13:02:59 +01006312
willy tarreau0f7af912005-12-17 12:21:26 +01006313/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006314 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006315 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006316int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006317
willy tarreau9fe663a2005-12-17 13:02:59 +01006318 if (!strcmp(args[0], "global")) { /* new section */
6319 /* no option, nothing special to do */
6320 return 0;
6321 }
6322 else if (!strcmp(args[0], "daemon")) {
6323 global.mode |= MODE_DAEMON;
6324 }
6325 else if (!strcmp(args[0], "debug")) {
6326 global.mode |= MODE_DEBUG;
6327 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006328 else if (!strcmp(args[0], "noepoll")) {
6329 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6330 }
6331 else if (!strcmp(args[0], "nopoll")) {
6332 cfg_polling_mechanism &= ~POLL_USE_POLL;
6333 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006334 else if (!strcmp(args[0], "quiet")) {
6335 global.mode |= MODE_QUIET;
6336 }
6337 else if (!strcmp(args[0], "stats")) {
6338 global.mode |= MODE_STATS;
6339 }
6340 else if (!strcmp(args[0], "uid")) {
6341 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006342 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006343 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006344 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006345 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006346 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006347 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006348 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006349 global.uid = atol(args[1]);
6350 }
6351 else if (!strcmp(args[0], "gid")) {
6352 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006353 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006354 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006355 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006356 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006357 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006358 return -1;
6359 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006360 global.gid = atol(args[1]);
6361 }
6362 else if (!strcmp(args[0], "nbproc")) {
6363 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006364 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006365 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006366 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006367 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006368 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006369 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006370 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006371 global.nbproc = atol(args[1]);
6372 }
6373 else if (!strcmp(args[0], "maxconn")) {
6374 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006375 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006376 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006377 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006378 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006379 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006380 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006381 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006382 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006383#ifdef SYSTEM_MAXCONN
6384 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6385 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);
6386 global.maxconn = DEFAULT_MAXCONN;
6387 }
6388#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006389 }
willy tarreaub1285d52005-12-18 01:20:14 +01006390 else if (!strcmp(args[0], "ulimit-n")) {
6391 if (global.rlimit_nofile != 0) {
6392 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6393 return 0;
6394 }
6395 if (*(args[1]) == 0) {
6396 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6397 return -1;
6398 }
6399 global.rlimit_nofile = atol(args[1]);
6400 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006401 else if (!strcmp(args[0], "chroot")) {
6402 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006403 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006404 return 0;
6405 }
6406 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006407 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006408 return -1;
6409 }
6410 global.chroot = strdup(args[1]);
6411 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006412 else if (!strcmp(args[0], "pidfile")) {
6413 if (global.pidfile != NULL) {
6414 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6415 return 0;
6416 }
6417 if (*(args[1]) == 0) {
6418 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6419 return -1;
6420 }
6421 global.pidfile = strdup(args[1]);
6422 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006423 else if (!strcmp(args[0], "log")) { /* syslog server address */
6424 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006425 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006426
6427 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006428 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006429 return -1;
6430 }
6431
6432 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6433 if (!strcmp(log_facilities[facility], args[2]))
6434 break;
6435
6436 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006437 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006438 exit(1);
6439 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006440
6441 level = 7; /* max syslog level = debug */
6442 if (*(args[3])) {
6443 while (level >= 0 && strcmp(log_levels[level], args[3]))
6444 level--;
6445 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006446 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006447 exit(1);
6448 }
6449 }
6450
willy tarreau9fe663a2005-12-17 13:02:59 +01006451 sa = str2sa(args[1]);
6452 if (!sa->sin_port)
6453 sa->sin_port = htons(SYSLOG_PORT);
6454
6455 if (global.logfac1 == -1) {
6456 global.logsrv1 = *sa;
6457 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006458 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006459 }
6460 else if (global.logfac2 == -1) {
6461 global.logsrv2 = *sa;
6462 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006463 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006464 }
6465 else {
6466 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6467 return -1;
6468 }
6469
6470 }
6471 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006472 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006473 return -1;
6474 }
6475 return 0;
6476}
6477
6478
willy tarreaua41a8b42005-12-17 14:02:24 +01006479void init_default_instance() {
6480 memset(&defproxy, 0, sizeof(defproxy));
6481 defproxy.mode = PR_MODE_TCP;
6482 defproxy.state = PR_STNEW;
6483 defproxy.maxconn = cfg_maxpconn;
6484 defproxy.conn_retries = CONN_RETRIES;
6485 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6486}
6487
willy tarreau9fe663a2005-12-17 13:02:59 +01006488/*
6489 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6490 */
6491int cfg_parse_listen(char *file, int linenum, char **args) {
6492 static struct proxy *curproxy = NULL;
6493 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006494 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006495 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006496
6497 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006498 if (!*args[1]) {
6499 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6500 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006501 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006502 return -1;
6503 }
6504
6505 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006506 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006507 return -1;
6508 }
6509 curproxy->next = proxy;
6510 proxy = curproxy;
6511 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006512
6513 /* parse the listener address if any */
6514 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006515 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006516 if (!curproxy->listen)
6517 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006518 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01006519 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006520
willy tarreau9fe663a2005-12-17 13:02:59 +01006521 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006522 curproxy->state = defproxy.state;
6523 curproxy->maxconn = defproxy.maxconn;
6524 curproxy->conn_retries = defproxy.conn_retries;
6525 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006526
6527 if (defproxy.check_req)
6528 curproxy->check_req = strdup(defproxy.check_req);
6529 curproxy->check_len = defproxy.check_len;
6530
6531 if (defproxy.cookie_name)
6532 curproxy->cookie_name = strdup(defproxy.cookie_name);
6533 curproxy->cookie_len = defproxy.cookie_len;
6534
6535 if (defproxy.capture_name)
6536 curproxy->capture_name = strdup(defproxy.capture_name);
6537 curproxy->capture_namelen = defproxy.capture_namelen;
6538 curproxy->capture_len = defproxy.capture_len;
6539
6540 if (defproxy.errmsg.msg400)
6541 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6542 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6543
6544 if (defproxy.errmsg.msg403)
6545 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6546 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6547
6548 if (defproxy.errmsg.msg408)
6549 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6550 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6551
6552 if (defproxy.errmsg.msg500)
6553 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6554 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6555
6556 if (defproxy.errmsg.msg502)
6557 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6558 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6559
6560 if (defproxy.errmsg.msg503)
6561 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6562 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6563
6564 if (defproxy.errmsg.msg504)
6565 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6566 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6567
willy tarreaua41a8b42005-12-17 14:02:24 +01006568 curproxy->clitimeout = defproxy.clitimeout;
6569 curproxy->contimeout = defproxy.contimeout;
6570 curproxy->srvtimeout = defproxy.srvtimeout;
6571 curproxy->mode = defproxy.mode;
6572 curproxy->logfac1 = defproxy.logfac1;
6573 curproxy->logsrv1 = defproxy.logsrv1;
6574 curproxy->loglev1 = defproxy.loglev1;
6575 curproxy->logfac2 = defproxy.logfac2;
6576 curproxy->logsrv2 = defproxy.logsrv2;
6577 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006578 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006579 curproxy->grace = defproxy.grace;
6580 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006581 curproxy->mon_net = defproxy.mon_net;
6582 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006583 return 0;
6584 }
6585 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006586 /* some variables may have already been initialized earlier */
6587 if (defproxy.check_req) free(defproxy.check_req);
6588 if (defproxy.cookie_name) free(defproxy.cookie_name);
6589 if (defproxy.capture_name) free(defproxy.capture_name);
6590 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6591 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6592 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6593 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6594 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6595 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6596 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6597
6598 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006599 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006600 return 0;
6601 }
6602 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006603 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006604 return -1;
6605 }
6606
willy tarreaua41a8b42005-12-17 14:02:24 +01006607 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6608 if (curproxy == &defproxy) {
6609 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6610 return -1;
6611 }
6612
6613 if (strchr(args[1], ':') == NULL) {
6614 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6615 file, linenum, args[0]);
6616 return -1;
6617 }
6618 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006619 if (!curproxy->listen)
6620 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006621 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006622 return 0;
6623 }
willy tarreaub1285d52005-12-18 01:20:14 +01006624 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6625 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6626 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6627 file, linenum, args[0]);
6628 return -1;
6629 }
6630 /* flush useless bits */
6631 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6632 return 0;
6633 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006634 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006635 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6636 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6637 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6638 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006639 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006640 return -1;
6641 }
6642 }
6643 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006644 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006645 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006646 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6647 curproxy->state = PR_STNEW;
6648 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006649 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6650 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006651// if (curproxy == &defproxy) {
6652// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6653// return -1;
6654// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006655
willy tarreau9fe663a2005-12-17 13:02:59 +01006656 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006657// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6658// file, linenum);
6659// return 0;
6660 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006661 }
6662
6663 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006664 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6665 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006666 return -1;
6667 }
6668 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006669 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006670
6671 cur_arg = 2;
6672 while (*(args[cur_arg])) {
6673 if (!strcmp(args[cur_arg], "rewrite")) {
6674 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006675 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006676 else if (!strcmp(args[cur_arg], "indirect")) {
6677 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006678 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006679 else if (!strcmp(args[cur_arg], "insert")) {
6680 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006681 }
willy tarreau240afa62005-12-17 13:14:35 +01006682 else if (!strcmp(args[cur_arg], "nocache")) {
6683 curproxy->options |= PR_O_COOK_NOC;
6684 }
willy tarreaucd878942005-12-17 13:27:43 +01006685 else if (!strcmp(args[cur_arg], "postonly")) {
6686 curproxy->options |= PR_O_COOK_POST;
6687 }
willy tarreau0174f312005-12-18 01:02:42 +01006688 else if (!strcmp(args[cur_arg], "prefix")) {
6689 curproxy->options |= PR_O_COOK_PFX;
6690 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006691 else {
willy tarreau0174f312005-12-18 01:02:42 +01006692 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006693 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006694 return -1;
6695 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006696 cur_arg++;
6697 }
willy tarreau0174f312005-12-18 01:02:42 +01006698 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6699 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6700 file, linenum);
6701 return -1;
6702 }
6703
6704 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6705 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006706 file, linenum);
6707 return -1;
6708 }
willy tarreau12350152005-12-18 01:03:27 +01006709 }/* end else if (!strcmp(args[0], "cookie")) */
6710 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6711// if (curproxy == &defproxy) {
6712// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6713// return -1;
6714// }
6715
6716 if (curproxy->appsession_name != NULL) {
6717// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6718// file, linenum);
6719// return 0;
6720 free(curproxy->appsession_name);
6721 }
6722
6723 if (*(args[5]) == 0) {
6724 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6725 file, linenum, args[0]);
6726 return -1;
6727 }
6728 have_appsession = 1;
6729 curproxy->appsession_name = strdup(args[1]);
6730 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6731 curproxy->appsession_len = atoi(args[3]);
6732 curproxy->appsession_timeout = atoi(args[5]);
6733 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6734 if (rc) {
6735 Alert("Error Init Appsession Hashtable.\n");
6736 return -1;
6737 }
6738 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006739 else if (!strcmp(args[0], "capture")) {
6740 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6741 // if (curproxy == &defproxy) {
6742 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6743 // return -1;
6744 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006745
willy tarreau4302f492005-12-18 01:00:37 +01006746 if (curproxy->capture_name != NULL) {
6747 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6748 // file, linenum, args[0]);
6749 // return 0;
6750 free(curproxy->capture_name);
6751 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006752
willy tarreau4302f492005-12-18 01:00:37 +01006753 if (*(args[4]) == 0) {
6754 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6755 file, linenum, args[0]);
6756 return -1;
6757 }
6758 curproxy->capture_name = strdup(args[2]);
6759 curproxy->capture_namelen = strlen(curproxy->capture_name);
6760 curproxy->capture_len = atol(args[4]);
6761 if (curproxy->capture_len >= CAPTURE_LEN) {
6762 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6763 file, linenum, CAPTURE_LEN - 1);
6764 curproxy->capture_len = CAPTURE_LEN - 1;
6765 }
6766 curproxy->to_log |= LW_COOKIE;
6767 }
6768 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6769 struct cap_hdr *hdr;
6770
6771 if (curproxy == &defproxy) {
6772 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6773 return -1;
6774 }
6775
6776 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6777 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6778 file, linenum, args[0], args[1]);
6779 return -1;
6780 }
6781
6782 hdr = calloc(sizeof(struct cap_hdr), 1);
6783 hdr->next = curproxy->req_cap;
6784 hdr->name = strdup(args[3]);
6785 hdr->namelen = strlen(args[3]);
6786 hdr->len = atol(args[5]);
6787 hdr->index = curproxy->nb_req_cap++;
6788 curproxy->req_cap = hdr;
6789 curproxy->to_log |= LW_REQHDR;
6790 }
6791 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6792 struct cap_hdr *hdr;
6793
6794 if (curproxy == &defproxy) {
6795 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6796 return -1;
6797 }
6798
6799 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6800 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6801 file, linenum, args[0], args[1]);
6802 return -1;
6803 }
6804 hdr = calloc(sizeof(struct cap_hdr), 1);
6805 hdr->next = curproxy->rsp_cap;
6806 hdr->name = strdup(args[3]);
6807 hdr->namelen = strlen(args[3]);
6808 hdr->len = atol(args[5]);
6809 hdr->index = curproxy->nb_rsp_cap++;
6810 curproxy->rsp_cap = hdr;
6811 curproxy->to_log |= LW_RSPHDR;
6812 }
6813 else {
6814 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006815 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006816 return -1;
6817 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006818 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006819 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006820 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006821 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006822 return 0;
6823 }
6824 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006825 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6826 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006827 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006828 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006829 curproxy->contimeout = atol(args[1]);
6830 }
6831 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006832 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006833 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6834 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006835 return 0;
6836 }
6837 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006838 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6839 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006840 return -1;
6841 }
6842 curproxy->clitimeout = atol(args[1]);
6843 }
6844 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006845 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006846 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006847 return 0;
6848 }
6849 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006850 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6851 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006852 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006853 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006854 curproxy->srvtimeout = atol(args[1]);
6855 }
6856 else if (!strcmp(args[0], "retries")) { /* connection retries */
6857 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006858 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6859 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006860 return -1;
6861 }
6862 curproxy->conn_retries = atol(args[1]);
6863 }
6864 else if (!strcmp(args[0], "option")) {
6865 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006866 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006867 return -1;
6868 }
6869 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006870 /* enable reconnections to dispatch */
6871 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006872#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006873 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006874 /* enable transparent proxy connections */
6875 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006876#endif
6877 else if (!strcmp(args[1], "keepalive"))
6878 /* enable keep-alive */
6879 curproxy->options |= PR_O_KEEPALIVE;
6880 else if (!strcmp(args[1], "forwardfor"))
6881 /* insert x-forwarded-for field */
6882 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006883 else if (!strcmp(args[1], "logasap"))
6884 /* log as soon as possible, without waiting for the session to complete */
6885 curproxy->options |= PR_O_LOGASAP;
6886 else if (!strcmp(args[1], "httpclose"))
6887 /* force connection: close in both directions in HTTP mode */
6888 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01006889 else if (!strcmp(args[1], "forceclose"))
6890 /* force connection: close in both directions in HTTP mode and enforce end of session */
6891 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006892 else if (!strcmp(args[1], "checkcache"))
6893 /* require examination of cacheability of the 'set-cookie' field */
6894 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006895 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006896 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006897 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006898 else if (!strcmp(args[1], "tcplog"))
6899 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006900 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006901 else if (!strcmp(args[1], "dontlognull")) {
6902 /* don't log empty requests */
6903 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006904 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006905 else if (!strcmp(args[1], "tcpka")) {
6906 /* enable TCP keep-alives on client and server sessions */
6907 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6908 }
6909 else if (!strcmp(args[1], "clitcpka")) {
6910 /* enable TCP keep-alives on client sessions */
6911 curproxy->options |= PR_O_TCP_CLI_KA;
6912 }
6913 else if (!strcmp(args[1], "srvtcpka")) {
6914 /* enable TCP keep-alives on server sessions */
6915 curproxy->options |= PR_O_TCP_SRV_KA;
6916 }
Willy TARREAU3481c462006-03-01 22:37:57 +01006917 else if (!strcmp(args[1], "allbackups")) {
6918 /* Use all backup servers simultaneously */
6919 curproxy->options |= PR_O_USE_ALL_BK;
6920 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006921 else if (!strcmp(args[1], "httpchk")) {
6922 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006923 if (curproxy->check_req != NULL) {
6924 free(curproxy->check_req);
6925 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006926 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006927 if (!*args[2]) { /* no argument */
6928 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6929 curproxy->check_len = strlen(DEF_CHECK_REQ);
6930 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006931 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6932 curproxy->check_req = (char *)malloc(reqlen);
6933 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6934 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006935 } else { /* more arguments : METHOD URI [HTTP_VER] */
6936 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6937 if (*args[4])
6938 reqlen += strlen(args[4]);
6939 else
6940 reqlen += strlen("HTTP/1.0");
6941
6942 curproxy->check_req = (char *)malloc(reqlen);
6943 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6944 "%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 +01006945 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006946 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006947 else if (!strcmp(args[1], "persist")) {
6948 /* persist on using the server specified by the cookie, even when it's down */
6949 curproxy->options |= PR_O_PERSIST;
6950 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006951 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006952 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006953 return -1;
6954 }
6955 return 0;
6956 }
6957 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6958 /* enable reconnections to dispatch */
6959 curproxy->options |= PR_O_REDISP;
6960 }
willy tarreaua1598082005-12-17 13:08:06 +01006961#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006962 else if (!strcmp(args[0], "transparent")) {
6963 /* enable transparent proxy connections */
6964 curproxy->options |= PR_O_TRANSP;
6965 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006966#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006967 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6968 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006969 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006970 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006971 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006972 curproxy->maxconn = atol(args[1]);
6973 }
6974 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6975 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006976 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006977 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006978 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006979 curproxy->grace = atol(args[1]);
6980 }
6981 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006982 if (curproxy == &defproxy) {
6983 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6984 return -1;
6985 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006986 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006987 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006988 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006989 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006990 curproxy->dispatch_addr = *str2sa(args[1]);
6991 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006992 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006993 if (*(args[1])) {
6994 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006995 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006996 }
willy tarreau1a3442d2006-03-24 21:03:20 +01006997 else if (!strcmp(args[1], "source")) {
6998 curproxy->options |= PR_O_BALANCE_SH;
6999 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007000 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01007001 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007002 return -1;
7003 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007004 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007005 else /* if no option is set, use round-robin by default */
7006 curproxy->options |= PR_O_BALANCE_RR;
7007 }
7008 else if (!strcmp(args[0], "server")) { /* server address */
7009 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007010 char *rport;
7011 char *raddr;
7012 short realport;
7013 int do_check;
7014
7015 if (curproxy == &defproxy) {
7016 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7017 return -1;
7018 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007019
willy tarreaua41a8b42005-12-17 14:02:24 +01007020 if (!*args[2]) {
7021 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007022 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007023 return -1;
7024 }
7025 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
7026 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7027 return -1;
7028 }
willy tarreau0174f312005-12-18 01:02:42 +01007029
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007030 /* the servers are linked backwards first */
7031 newsrv->next = curproxy->srv;
7032 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01007033 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007034
7035 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01007036 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01007037 newsrv->id = strdup(args[1]);
7038
7039 /* several ways to check the port component :
7040 * - IP => port=+0, relative
7041 * - IP: => port=+0, relative
7042 * - IP:N => port=N, absolute
7043 * - IP:+N => port=+N, relative
7044 * - IP:-N => port=-N, relative
7045 */
7046 raddr = strdup(args[2]);
7047 rport = strchr(raddr, ':');
7048 if (rport) {
7049 *rport++ = 0;
7050 realport = atol(rport);
7051 if (!isdigit((int)*rport))
7052 newsrv->state |= SRV_MAPPORTS;
7053 } else {
7054 realport = 0;
7055 newsrv->state |= SRV_MAPPORTS;
7056 }
7057
7058 newsrv->addr = *str2sa(raddr);
7059 newsrv->addr.sin_port = htons(realport);
7060 free(raddr);
7061
willy tarreau9fe663a2005-12-17 13:02:59 +01007062 newsrv->curfd = -1; /* no health-check in progress */
7063 newsrv->inter = DEF_CHKINTR;
7064 newsrv->rise = DEF_RISETIME;
7065 newsrv->fall = DEF_FALLTIME;
7066 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7067 cur_arg = 3;
7068 while (*args[cur_arg]) {
7069 if (!strcmp(args[cur_arg], "cookie")) {
7070 newsrv->cookie = strdup(args[cur_arg + 1]);
7071 newsrv->cklen = strlen(args[cur_arg + 1]);
7072 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007073 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007074 else if (!strcmp(args[cur_arg], "rise")) {
7075 newsrv->rise = atol(args[cur_arg + 1]);
7076 newsrv->health = newsrv->rise;
7077 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007078 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007079 else if (!strcmp(args[cur_arg], "fall")) {
7080 newsrv->fall = atol(args[cur_arg + 1]);
7081 cur_arg += 2;
7082 }
7083 else if (!strcmp(args[cur_arg], "inter")) {
7084 newsrv->inter = atol(args[cur_arg + 1]);
7085 cur_arg += 2;
7086 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007087 else if (!strcmp(args[cur_arg], "port")) {
7088 newsrv->check_port = atol(args[cur_arg + 1]);
7089 cur_arg += 2;
7090 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007091 else if (!strcmp(args[cur_arg], "backup")) {
7092 newsrv->state |= SRV_BACKUP;
7093 cur_arg ++;
7094 }
willy tarreaue3f023f2006-04-08 21:52:24 +02007095 else if (!strcmp(args[cur_arg], "weight")) {
7096 int w;
7097 w = atol(args[cur_arg + 1]);
7098 if (w < 1 || w > 256) {
7099 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
7100 file, linenum, newsrv->id, w);
7101 return -1;
7102 }
7103 newsrv->uweight = w - 1;
7104 cur_arg += 2;
7105 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007106 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007107 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007108 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007109 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007110 }
willy tarreau0174f312005-12-18 01:02:42 +01007111 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7112 if (!*args[cur_arg + 1]) {
7113 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7114 file, linenum, "source");
7115 return -1;
7116 }
7117 newsrv->state |= SRV_BIND_SRC;
7118 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7119 cur_arg += 2;
7120 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007121 else {
willy tarreaue3f023f2006-04-08 21:52:24 +02007122 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port', 'source', and 'weight'.\n",
willy tarreaua41a8b42005-12-17 14:02:24 +01007123 file, linenum, newsrv->id);
7124 return -1;
7125 }
7126 }
7127
7128 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007129 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7130 newsrv->check_port = realport; /* by default */
7131 if (!newsrv->check_port) {
7132 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 +01007133 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007134 return -1;
7135 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007136 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007137 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007138
willy tarreau62084d42006-03-24 18:57:41 +01007139 if (newsrv->state & SRV_BACKUP)
7140 curproxy->srv_bck++;
7141 else
7142 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007143 }
7144 else if (!strcmp(args[0], "log")) { /* syslog server address */
7145 struct sockaddr_in *sa;
7146 int facility;
7147
7148 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7149 curproxy->logfac1 = global.logfac1;
7150 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007151 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007152 curproxy->logfac2 = global.logfac2;
7153 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007154 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007155 }
7156 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007157 int level;
7158
willy tarreau0f7af912005-12-17 12:21:26 +01007159 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7160 if (!strcmp(log_facilities[facility], args[2]))
7161 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007162
willy tarreau0f7af912005-12-17 12:21:26 +01007163 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007164 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007165 exit(1);
7166 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007167
willy tarreau8337c6b2005-12-17 13:41:01 +01007168 level = 7; /* max syslog level = debug */
7169 if (*(args[3])) {
7170 while (level >= 0 && strcmp(log_levels[level], args[3]))
7171 level--;
7172 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007173 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007174 exit(1);
7175 }
7176 }
7177
willy tarreau0f7af912005-12-17 12:21:26 +01007178 sa = str2sa(args[1]);
7179 if (!sa->sin_port)
7180 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007181
willy tarreau0f7af912005-12-17 12:21:26 +01007182 if (curproxy->logfac1 == -1) {
7183 curproxy->logsrv1 = *sa;
7184 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007185 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007186 }
7187 else if (curproxy->logfac2 == -1) {
7188 curproxy->logsrv2 = *sa;
7189 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007190 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007191 }
7192 else {
7193 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007194 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007195 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007196 }
7197 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007198 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007199 file, linenum);
7200 return -1;
7201 }
7202 }
willy tarreaua1598082005-12-17 13:08:06 +01007203 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007204 if (!*args[1]) {
7205 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007206 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007207 return -1;
7208 }
7209
7210 curproxy->source_addr = *str2sa(args[1]);
7211 curproxy->options |= PR_O_BIND_SRC;
7212 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007213 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7214 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007215 if (curproxy == &defproxy) {
7216 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7217 return -1;
7218 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007219
7220 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007221 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7222 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007223 return -1;
7224 }
7225
7226 preg = calloc(1, sizeof(regex_t));
7227 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007228 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007229 return -1;
7230 }
7231
willy tarreauc1f47532005-12-18 01:08:26 +01007232 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7233 if (err) {
7234 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7235 file, linenum, *err);
7236 return -1;
7237 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007238 }
7239 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7240 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007241 if (curproxy == &defproxy) {
7242 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7243 return -1;
7244 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007245
7246 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007247 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007248 return -1;
7249 }
7250
7251 preg = calloc(1, sizeof(regex_t));
7252 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007253 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007254 return -1;
7255 }
7256
7257 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7258 }
7259 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7260 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007261 if (curproxy == &defproxy) {
7262 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7263 return -1;
7264 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007265
7266 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007267 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007268 return -1;
7269 }
7270
7271 preg = calloc(1, sizeof(regex_t));
7272 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007273 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007274 return -1;
7275 }
7276
7277 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7278 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007279 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7280 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007281 if (curproxy == &defproxy) {
7282 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7283 return -1;
7284 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007285
7286 if (*(args[1]) == 0) {
7287 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7288 return -1;
7289 }
7290
7291 preg = calloc(1, sizeof(regex_t));
7292 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7293 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7294 return -1;
7295 }
7296
7297 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7298 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007299 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7300 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007301 if (curproxy == &defproxy) {
7302 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7303 return -1;
7304 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007305
7306 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007307 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007308 return -1;
7309 }
7310
7311 preg = calloc(1, sizeof(regex_t));
7312 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007313 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007314 return -1;
7315 }
7316
7317 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7318 }
7319 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7320 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007321 if (curproxy == &defproxy) {
7322 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7323 return -1;
7324 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007325
7326 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007327 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7328 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007329 return -1;
7330 }
7331
7332 preg = calloc(1, sizeof(regex_t));
7333 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007334 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007335 return -1;
7336 }
7337
willy tarreauc1f47532005-12-18 01:08:26 +01007338 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7339 if (err) {
7340 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7341 file, linenum, *err);
7342 return -1;
7343 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007344 }
7345 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7346 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007347 if (curproxy == &defproxy) {
7348 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7349 return -1;
7350 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007351
7352 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007353 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007354 return -1;
7355 }
7356
7357 preg = calloc(1, sizeof(regex_t));
7358 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007359 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007360 return -1;
7361 }
7362
7363 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7364 }
7365 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7366 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007367 if (curproxy == &defproxy) {
7368 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7369 return -1;
7370 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007371
7372 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007373 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007374 return -1;
7375 }
7376
7377 preg = calloc(1, sizeof(regex_t));
7378 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007379 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007380 return -1;
7381 }
7382
7383 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7384 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007385 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7386 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007387 if (curproxy == &defproxy) {
7388 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7389 return -1;
7390 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007391
7392 if (*(args[1]) == 0) {
7393 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7394 return -1;
7395 }
7396
7397 preg = calloc(1, sizeof(regex_t));
7398 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7399 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7400 return -1;
7401 }
7402
7403 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7404 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007405 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7406 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007407 if (curproxy == &defproxy) {
7408 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7409 return -1;
7410 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007411
7412 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007413 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007414 return -1;
7415 }
7416
7417 preg = calloc(1, sizeof(regex_t));
7418 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007419 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007420 return -1;
7421 }
7422
7423 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7424 }
7425 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007426 if (curproxy == &defproxy) {
7427 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7428 return -1;
7429 }
7430
willy tarreau9fe663a2005-12-17 13:02:59 +01007431 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007432 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007433 return 0;
7434 }
7435
7436 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007437 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007438 return -1;
7439 }
7440
willy tarreau4302f492005-12-18 01:00:37 +01007441 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7442 }
7443 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7444 regex_t *preg;
7445
7446 if (*(args[1]) == 0 || *(args[2]) == 0) {
7447 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7448 file, linenum, args[0]);
7449 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007450 }
willy tarreau4302f492005-12-18 01:00:37 +01007451
7452 preg = calloc(1, sizeof(regex_t));
7453 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7454 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7455 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007456 }
willy tarreau4302f492005-12-18 01:00:37 +01007457
willy tarreauc1f47532005-12-18 01:08:26 +01007458 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7459 if (err) {
7460 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7461 file, linenum, *err);
7462 return -1;
7463 }
willy tarreau4302f492005-12-18 01:00:37 +01007464 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007465 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7466 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007467 if (curproxy == &defproxy) {
7468 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7469 return -1;
7470 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007471
7472 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007473 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007474 return -1;
7475 }
willy tarreaue39cd132005-12-17 13:00:18 +01007476
willy tarreau9fe663a2005-12-17 13:02:59 +01007477 preg = calloc(1, sizeof(regex_t));
7478 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007479 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007480 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007481 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007482
willy tarreauc1f47532005-12-18 01:08:26 +01007483 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7484 if (err) {
7485 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7486 file, linenum, *err);
7487 return -1;
7488 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007489 }
willy tarreau982249e2005-12-18 00:57:06 +01007490 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7491 regex_t *preg;
7492 if (curproxy == &defproxy) {
7493 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7494 return -1;
7495 }
7496
7497 if (*(args[1]) == 0) {
7498 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7499 return -1;
7500 }
7501
7502 preg = calloc(1, sizeof(regex_t));
7503 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7504 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7505 return -1;
7506 }
7507
willy tarreauc1f47532005-12-18 01:08:26 +01007508 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7509 if (err) {
7510 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7511 file, linenum, *err);
7512 return -1;
7513 }
willy tarreau982249e2005-12-18 00:57:06 +01007514 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007515 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007516 regex_t *preg;
7517 if (curproxy == &defproxy) {
7518 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7519 return -1;
7520 }
willy tarreaue39cd132005-12-17 13:00:18 +01007521
willy tarreaua41a8b42005-12-17 14:02:24 +01007522 if (*(args[1]) == 0 || *(args[2]) == 0) {
7523 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7524 file, linenum, args[0]);
7525 return -1;
7526 }
willy tarreaue39cd132005-12-17 13:00:18 +01007527
willy tarreaua41a8b42005-12-17 14:02:24 +01007528 preg = calloc(1, sizeof(regex_t));
7529 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7530 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7531 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007532 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007533
willy tarreauc1f47532005-12-18 01:08:26 +01007534 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7535 if (err) {
7536 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7537 file, linenum, *err);
7538 return -1;
7539 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007540 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007541 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7542 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007543 if (curproxy == &defproxy) {
7544 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7545 return -1;
7546 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007547
7548 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007549 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007550 return -1;
7551 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007552
willy tarreau9fe663a2005-12-17 13:02:59 +01007553 preg = calloc(1, sizeof(regex_t));
7554 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007555 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007556 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007557 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007558
willy tarreauc1f47532005-12-18 01:08:26 +01007559 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7560 if (err) {
7561 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7562 file, linenum, *err);
7563 return -1;
7564 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007565 }
willy tarreau982249e2005-12-18 00:57:06 +01007566 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7567 regex_t *preg;
7568 if (curproxy == &defproxy) {
7569 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7570 return -1;
7571 }
7572
7573 if (*(args[1]) == 0) {
7574 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7575 return -1;
7576 }
7577
7578 preg = calloc(1, sizeof(regex_t));
7579 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7580 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7581 return -1;
7582 }
7583
willy tarreauc1f47532005-12-18 01:08:26 +01007584 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7585 if (err) {
7586 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7587 file, linenum, *err);
7588 return -1;
7589 }
willy tarreau982249e2005-12-18 00:57:06 +01007590 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007591 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007592 if (curproxy == &defproxy) {
7593 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7594 return -1;
7595 }
7596
willy tarreau9fe663a2005-12-17 13:02:59 +01007597 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007598 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007599 return 0;
7600 }
7601
7602 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007603 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007604 return -1;
7605 }
7606
7607 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7608 }
willy tarreauc1f47532005-12-18 01:08:26 +01007609 else if (!strcmp(args[0], "errorloc") ||
7610 !strcmp(args[0], "errorloc302") ||
7611 !strcmp(args[0], "errorloc303")) { /* error location */
7612 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007613 char *err;
7614
willy tarreaueedaa9f2005-12-17 14:08:03 +01007615 // if (curproxy == &defproxy) {
7616 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7617 // return -1;
7618 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007619
willy tarreau8337c6b2005-12-17 13:41:01 +01007620 if (*(args[2]) == 0) {
7621 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7622 return -1;
7623 }
7624
7625 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007626 if (!strcmp(args[0], "errorloc303")) {
7627 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7628 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7629 } else {
7630 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7631 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7632 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007633
7634 if (errnum == 400) {
7635 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007636 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007637 free(curproxy->errmsg.msg400);
7638 }
7639 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007640 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007641 }
7642 else if (errnum == 403) {
7643 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007644 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007645 free(curproxy->errmsg.msg403);
7646 }
7647 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007648 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007649 }
7650 else if (errnum == 408) {
7651 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007652 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007653 free(curproxy->errmsg.msg408);
7654 }
7655 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007656 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007657 }
7658 else if (errnum == 500) {
7659 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007660 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007661 free(curproxy->errmsg.msg500);
7662 }
7663 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007664 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007665 }
7666 else if (errnum == 502) {
7667 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007668 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007669 free(curproxy->errmsg.msg502);
7670 }
7671 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007672 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007673 }
7674 else if (errnum == 503) {
7675 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007676 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007677 free(curproxy->errmsg.msg503);
7678 }
7679 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007680 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007681 }
7682 else if (errnum == 504) {
7683 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007684 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007685 free(curproxy->errmsg.msg504);
7686 }
7687 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007688 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007689 }
7690 else {
7691 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7692 free(err);
7693 }
7694 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007695 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007696 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007697 return -1;
7698 }
7699 return 0;
7700}
willy tarreaue39cd132005-12-17 13:00:18 +01007701
willy tarreau5cbea6f2005-12-17 12:48:26 +01007702
willy tarreau9fe663a2005-12-17 13:02:59 +01007703/*
7704 * This function reads and parses the configuration file given in the argument.
7705 * returns 0 if OK, -1 if error.
7706 */
7707int readcfgfile(char *file) {
7708 char thisline[256];
7709 char *line;
7710 FILE *f;
7711 int linenum = 0;
7712 char *end;
7713 char *args[MAX_LINE_ARGS];
7714 int arg;
7715 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007716 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007717 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007718
willy tarreau9fe663a2005-12-17 13:02:59 +01007719 struct proxy *curproxy = NULL;
7720 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007721
willy tarreau9fe663a2005-12-17 13:02:59 +01007722 if ((f=fopen(file,"r")) == NULL)
7723 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007724
willy tarreaueedaa9f2005-12-17 14:08:03 +01007725 init_default_instance();
7726
willy tarreau9fe663a2005-12-17 13:02:59 +01007727 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7728 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007729
willy tarreau9fe663a2005-12-17 13:02:59 +01007730 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007731
willy tarreau9fe663a2005-12-17 13:02:59 +01007732 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007733 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007734 line++;
7735
7736 arg = 0;
7737 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007738
willy tarreau9fe663a2005-12-17 13:02:59 +01007739 while (*line && arg < MAX_LINE_ARGS) {
7740 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7741 * C equivalent value. Other combinations left unchanged (eg: \1).
7742 */
7743 if (*line == '\\') {
7744 int skip = 0;
7745 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7746 *line = line[1];
7747 skip = 1;
7748 }
7749 else if (line[1] == 'r') {
7750 *line = '\r';
7751 skip = 1;
7752 }
7753 else if (line[1] == 'n') {
7754 *line = '\n';
7755 skip = 1;
7756 }
7757 else if (line[1] == 't') {
7758 *line = '\t';
7759 skip = 1;
7760 }
willy tarreauc1f47532005-12-18 01:08:26 +01007761 else if (line[1] == 'x') {
7762 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7763 unsigned char hex1, hex2;
7764 hex1 = toupper(line[2]) - '0';
7765 hex2 = toupper(line[3]) - '0';
7766 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7767 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7768 *line = (hex1<<4) + hex2;
7769 skip = 3;
7770 }
7771 else {
7772 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7773 return -1;
7774 }
7775 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007776 if (skip) {
7777 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7778 end -= skip;
7779 }
7780 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007781 }
willy tarreaua1598082005-12-17 13:08:06 +01007782 else if (*line == '#' || *line == '\n' || *line == '\r') {
7783 /* end of string, end of loop */
7784 *line = 0;
7785 break;
7786 }
willy tarreauc29948c2005-12-17 13:10:27 +01007787 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007788 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007789 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007790 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007791 line++;
7792 args[++arg] = line;
7793 }
7794 else {
7795 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007796 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007797 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007798
willy tarreau9fe663a2005-12-17 13:02:59 +01007799 /* empty line */
7800 if (!**args)
7801 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007802
willy tarreau9fe663a2005-12-17 13:02:59 +01007803 /* zero out remaining args */
7804 while (++arg < MAX_LINE_ARGS) {
7805 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007806 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007807
willy tarreaua41a8b42005-12-17 14:02:24 +01007808 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007809 confsect = CFG_LISTEN;
7810 else if (!strcmp(args[0], "global")) /* global config */
7811 confsect = CFG_GLOBAL;
7812 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007813
willy tarreau9fe663a2005-12-17 13:02:59 +01007814 switch (confsect) {
7815 case CFG_LISTEN:
7816 if (cfg_parse_listen(file, linenum, args) < 0)
7817 return -1;
7818 break;
7819 case CFG_GLOBAL:
7820 if (cfg_parse_global(file, linenum, args) < 0)
7821 return -1;
7822 break;
7823 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007824 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007825 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007826 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007827
7828
willy tarreau0f7af912005-12-17 12:21:26 +01007829 }
7830 fclose(f);
7831
7832 /*
7833 * Now, check for the integrity of all that we have collected.
7834 */
7835
Willy TARREAU3759f982006-03-01 22:44:17 +01007836 /* will be needed further to delay some tasks */
7837 tv_now(&now);
7838
willy tarreau0f7af912005-12-17 12:21:26 +01007839 if ((curproxy = proxy) == NULL) {
7840 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7841 file);
7842 return -1;
7843 }
7844
7845 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007846 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007847 curproxy = curproxy->next;
7848 continue;
7849 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007850
7851 if (curproxy->listen == NULL) {
7852 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);
7853 cfgerr++;
7854 }
7855 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007856 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007857 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007858 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7859 file, curproxy->id);
7860 cfgerr++;
7861 }
7862 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7863 if (curproxy->options & PR_O_TRANSP) {
7864 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7865 file, curproxy->id);
7866 cfgerr++;
7867 }
7868 else if (curproxy->srv == NULL) {
7869 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7870 file, curproxy->id);
7871 cfgerr++;
7872 }
willy tarreaua1598082005-12-17 13:08:06 +01007873 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007874 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7875 file, curproxy->id);
7876 }
7877 }
7878 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007879 if (curproxy->cookie_name != NULL) {
7880 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7881 file, curproxy->id);
7882 }
7883 if ((newsrv = curproxy->srv) != NULL) {
7884 Warning("parsing %s : servers will be ignored for listener %s.\n",
7885 file, curproxy->id);
7886 }
willy tarreaue39cd132005-12-17 13:00:18 +01007887 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007888 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7889 file, curproxy->id);
7890 }
willy tarreaue39cd132005-12-17 13:00:18 +01007891 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007892 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7893 file, curproxy->id);
7894 }
7895 }
7896 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7897 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7898 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7899 file, curproxy->id);
7900 cfgerr++;
7901 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007902 }
willy tarreaue3f023f2006-04-08 21:52:24 +02007903
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007904 /* first, we will invert the servers list order */
7905 newsrv = NULL;
7906 while (curproxy->srv) {
7907 struct server *next;
7908
7909 next = curproxy->srv->next;
7910 curproxy->srv->next = newsrv;
7911 newsrv = curproxy->srv;
7912 if (!next)
7913 break;
7914 curproxy->srv = next;
7915 }
7916
7917 /* now, newsrv == curproxy->srv */
7918 if (newsrv) {
7919 struct server *srv;
7920 int pgcd;
7921 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02007922
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007923 /* We will factor the weights to reduce the table,
7924 * using Euclide's largest common divisor algorithm
7925 */
7926 pgcd = newsrv->uweight + 1;
7927 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
7928 int t, w;
7929
7930 w = srv->uweight + 1;
7931 while (w) {
7932 t = pgcd % w;
7933 pgcd = w;
7934 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02007935 }
willy tarreau0f7af912005-12-17 12:21:26 +01007936 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007937
7938 act = bck = 0;
7939 for (srv = newsrv; srv; srv = srv->next) {
7940 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
7941 if (srv->state & SRV_BACKUP)
7942 bck += srv->eweight + 1;
7943 else
7944 act += srv->eweight + 1;
7945 }
7946
7947 /* this is the largest map we will ever need for this servers list */
7948 if (act < bck)
7949 act = bck;
7950
7951 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
7952 /* recounts servers and their weights */
7953 recount_servers(curproxy);
7954 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01007955 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007956
7957 if (curproxy->options & PR_O_LOGASAP)
7958 curproxy->to_log &= ~LW_BYTES;
7959
willy tarreau8337c6b2005-12-17 13:41:01 +01007960 if (curproxy->errmsg.msg400 == NULL) {
7961 curproxy->errmsg.msg400 = (char *)HTTP_400;
7962 curproxy->errmsg.len400 = strlen(HTTP_400);
7963 }
7964 if (curproxy->errmsg.msg403 == NULL) {
7965 curproxy->errmsg.msg403 = (char *)HTTP_403;
7966 curproxy->errmsg.len403 = strlen(HTTP_403);
7967 }
7968 if (curproxy->errmsg.msg408 == NULL) {
7969 curproxy->errmsg.msg408 = (char *)HTTP_408;
7970 curproxy->errmsg.len408 = strlen(HTTP_408);
7971 }
7972 if (curproxy->errmsg.msg500 == NULL) {
7973 curproxy->errmsg.msg500 = (char *)HTTP_500;
7974 curproxy->errmsg.len500 = strlen(HTTP_500);
7975 }
7976 if (curproxy->errmsg.msg502 == NULL) {
7977 curproxy->errmsg.msg502 = (char *)HTTP_502;
7978 curproxy->errmsg.len502 = strlen(HTTP_502);
7979 }
7980 if (curproxy->errmsg.msg503 == NULL) {
7981 curproxy->errmsg.msg503 = (char *)HTTP_503;
7982 curproxy->errmsg.len503 = strlen(HTTP_503);
7983 }
7984 if (curproxy->errmsg.msg504 == NULL) {
7985 curproxy->errmsg.msg504 = (char *)HTTP_504;
7986 curproxy->errmsg.len504 = strlen(HTTP_504);
7987 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007988
7989 /* now we'll start this proxy's health checks if any */
7990 /* 1- count the checkers to run simultaneously */
7991 nbchk = 0;
7992 mininter = 0;
7993 newsrv = curproxy->srv;
7994 while (newsrv != NULL) {
7995 if (newsrv->state & SRV_CHECKED) {
7996 if (!mininter || mininter > newsrv->inter)
7997 mininter = newsrv->inter;
7998 nbchk++;
7999 }
8000 newsrv = newsrv->next;
8001 }
8002
8003 /* 2- start them as far as possible from each others while respecting
8004 * their own intervals. For this, we will start them after their own
8005 * interval added to the min interval divided by the number of servers,
8006 * weighted by the server's position in the list.
8007 */
8008 if (nbchk > 0) {
8009 struct task *t;
8010 int srvpos;
8011
8012 newsrv = curproxy->srv;
8013 srvpos = 0;
8014 while (newsrv != NULL) {
8015 /* should this server be checked ? */
8016 if (newsrv->state & SRV_CHECKED) {
8017 if ((t = pool_alloc(task)) == NULL) {
8018 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8019 return -1;
8020 }
8021
8022 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
8023 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
8024 t->state = TASK_IDLE;
8025 t->process = process_chk;
8026 t->context = newsrv;
8027
8028 /* check this every ms */
8029 tv_delayfrom(&t->expire, &now,
8030 newsrv->inter + mininter * srvpos / nbchk);
8031 task_queue(t);
8032 //task_wakeup(&rq, t);
8033 srvpos++;
8034 }
8035 newsrv = newsrv->next;
8036 }
8037 }
8038
willy tarreau0f7af912005-12-17 12:21:26 +01008039 curproxy = curproxy->next;
8040 }
8041 if (cfgerr > 0) {
8042 Alert("Errors found in configuration file, aborting.\n");
8043 return -1;
8044 }
8045 else
8046 return 0;
8047}
8048
8049
8050/*
8051 * This function initializes all the necessary variables. It only returns
8052 * if everything is OK. If something fails, it exits.
8053 */
8054void init(int argc, char **argv) {
8055 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01008056 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01008057 char *old_argv = *argv;
8058 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008059 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008060
8061 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01008062 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01008063 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01008064 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01008065 exit(1);
8066 }
8067
willy tarreau746e26b2006-03-25 11:14:35 +01008068#ifdef HAPROXY_MEMMAX
8069 global.rlimit_memmax = HAPROXY_MEMMAX;
8070#endif
8071
Willy TARREAUa9e75f62006-03-01 22:27:48 +01008072 /* initialize the libc's localtime structures once for all so that we
8073 * won't be missing memory if we want to send alerts under OOM conditions.
8074 */
8075 tv_now(&now);
8076 localtime(&now.tv_sec);
8077
willy tarreau4302f492005-12-18 01:00:37 +01008078 /* initialize the log header encoding map : '{|}"#' should be encoded with
8079 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
8080 * URL encoding only requires '"', '#' to be encoded as well as non-
8081 * printable characters above.
8082 */
8083 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
8084 memset(url_encode_map, 0, sizeof(url_encode_map));
8085 for (i = 0; i < 32; i++) {
8086 FD_SET(i, hdr_encode_map);
8087 FD_SET(i, url_encode_map);
8088 }
8089 for (i = 127; i < 256; i++) {
8090 FD_SET(i, hdr_encode_map);
8091 FD_SET(i, url_encode_map);
8092 }
8093
8094 tmp = "\"#{|}";
8095 while (*tmp) {
8096 FD_SET(*tmp, hdr_encode_map);
8097 tmp++;
8098 }
8099
8100 tmp = "\"#";
8101 while (*tmp) {
8102 FD_SET(*tmp, url_encode_map);
8103 tmp++;
8104 }
8105
willy tarreau64a3cc32005-12-18 01:13:11 +01008106 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8107#if defined(ENABLE_POLL)
8108 cfg_polling_mechanism |= POLL_USE_POLL;
8109#endif
8110#if defined(ENABLE_EPOLL)
8111 cfg_polling_mechanism |= POLL_USE_EPOLL;
8112#endif
8113
willy tarreau0f7af912005-12-17 12:21:26 +01008114 pid = getpid();
8115 progname = *argv;
8116 while ((tmp = strchr(progname, '/')) != NULL)
8117 progname = tmp + 1;
8118
8119 argc--; argv++;
8120 while (argc > 0) {
8121 char *flag;
8122
8123 if (**argv == '-') {
8124 flag = *argv+1;
8125
8126 /* 1 arg */
8127 if (*flag == 'v') {
8128 display_version();
8129 exit(0);
8130 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008131#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008132 else if (*flag == 'd' && flag[1] == 'e')
8133 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008134#endif
8135#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008136 else if (*flag == 'd' && flag[1] == 'p')
8137 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008138#endif
willy tarreau982249e2005-12-18 00:57:06 +01008139 else if (*flag == 'V')
8140 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008141 else if (*flag == 'd' && flag[1] == 'b')
8142 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008143 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008144 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008145 else if (*flag == 'c')
8146 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008147 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008148 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008149 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008150 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01008151 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8152 /* list of pids to finish ('f') or terminate ('t') */
8153
8154 if (flag[1] == 'f')
8155 oldpids_sig = SIGUSR1; /* finish then exit */
8156 else
8157 oldpids_sig = SIGTERM; /* terminate immediately */
8158 argv++; argc--;
8159
8160 if (argc > 0) {
8161 oldpids = calloc(argc, sizeof(int));
8162 while (argc > 0) {
8163 oldpids[nb_oldpids] = atol(*argv);
8164 if (oldpids[nb_oldpids] <= 0)
8165 usage(old_argv);
8166 argc--; argv++;
8167 nb_oldpids++;
8168 }
8169 }
8170 }
willy tarreau2c513732006-04-15 19:25:16 +02008171#if STATTIME > 0
8172 else if (*flag == 's')
8173 arg_mode |= MODE_STATS;
8174 else if (*flag == 'l')
8175 arg_mode |= MODE_LOG;
8176#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008177 else { /* >=2 args */
8178 argv++; argc--;
8179 if (argc == 0)
8180 usage(old_argv);
8181
8182 switch (*flag) {
8183 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008184 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008185 case 'N' : cfg_maxpconn = atol(*argv); break;
8186 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008187 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008188 default: usage(old_argv);
8189 }
8190 }
8191 }
8192 else
8193 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008194 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008195 }
8196
willy tarreaud0fb4652005-12-18 01:32:04 +01008197 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008198 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8199 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008200
willy tarreau0f7af912005-12-17 12:21:26 +01008201 if (!cfg_cfgfile)
8202 usage(old_argv);
8203
8204 gethostname(hostname, MAX_HOSTNAME_LEN);
8205
willy tarreau12350152005-12-18 01:03:27 +01008206 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008207 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008208 if (readcfgfile(cfg_cfgfile) < 0) {
8209 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8210 exit(1);
8211 }
willy tarreau12350152005-12-18 01:03:27 +01008212 if (have_appsession)
8213 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008214
willy tarreau982249e2005-12-18 00:57:06 +01008215 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008216 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8217 exit(0);
8218 }
8219
willy tarreau9fe663a2005-12-17 13:02:59 +01008220 if (cfg_maxconn > 0)
8221 global.maxconn = cfg_maxconn;
8222
willy tarreaufe2c5c12005-12-17 14:14:34 +01008223 if (cfg_pidfile) {
8224 if (global.pidfile)
8225 free(global.pidfile);
8226 global.pidfile = strdup(cfg_pidfile);
8227 }
8228
willy tarreau9fe663a2005-12-17 13:02:59 +01008229 if (global.maxconn == 0)
8230 global.maxconn = DEFAULT_MAXCONN;
8231
Willy TARREAU203b0b62006-03-12 18:00:28 +01008232 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008233
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008234 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008235 /* command line debug mode inhibits configuration mode */
8236 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8237 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008238 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8239 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008240
8241 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8242 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8243 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8244 }
8245
8246 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008247 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8248 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008249 global.nbproc = 1;
8250 }
8251
8252 if (global.nbproc < 1)
8253 global.nbproc = 1;
8254
willy tarreau0f7af912005-12-17 12:21:26 +01008255 StaticReadEvent = (fd_set *)calloc(1,
8256 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008257 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008258 StaticWriteEvent = (fd_set *)calloc(1,
8259 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008260 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008261
8262 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008263 sizeof(struct fdtab) * (global.maxsock));
8264 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008265 fdtab[i].state = FD_STCLOSE;
8266 }
8267}
8268
8269/*
willy tarreau41310e72006-03-25 18:17:56 +01008270 * this function starts all the proxies. Its return value is composed from
8271 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8272 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008273 */
willy tarreau41310e72006-03-25 18:17:56 +01008274int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008275 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008276 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008277 int err = ERR_NONE;
8278 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008279
8280 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008281 if (curproxy->state != PR_STNEW)
8282 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01008283
willy tarreau41310e72006-03-25 18:17:56 +01008284 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01008285 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008286 if (listener->fd != -1)
8287 continue; /* already initialized */
8288
8289 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
8290 if (verbose)
8291 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8292 curproxy->id);
8293 err |= ERR_RETRYABLE;
8294 pxerr |= 1;
8295 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008296 }
willy tarreau0f7af912005-12-17 12:21:26 +01008297
willy tarreaua41a8b42005-12-17 14:02:24 +01008298 if (fd >= global.maxsock) {
8299 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
8300 curproxy->id);
8301 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008302 err |= ERR_FATAL;
8303 pxerr |= 1;
8304 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008305 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008306
willy tarreaua41a8b42005-12-17 14:02:24 +01008307 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
8308 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
8309 (char *) &one, sizeof(one)) == -1)) {
8310 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
8311 curproxy->id);
8312 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008313 err |= ERR_FATAL;
8314 pxerr |= 1;
8315 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008316 }
willy tarreau0f7af912005-12-17 12:21:26 +01008317
willy tarreaua41a8b42005-12-17 14:02:24 +01008318 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8319 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8320 curproxy->id);
8321 }
willy tarreau0f7af912005-12-17 12:21:26 +01008322
willy tarreaua41a8b42005-12-17 14:02:24 +01008323 if (bind(fd,
8324 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008325 listener->addr.ss_family == AF_INET6 ?
8326 sizeof(struct sockaddr_in6) :
8327 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008328 if (verbose)
8329 Alert("cannot bind socket for proxy %s. Aborting.\n",
8330 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008331 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008332 err |= ERR_RETRYABLE;
8333 pxerr |= 1;
8334 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008335 }
willy tarreau0f7af912005-12-17 12:21:26 +01008336
willy tarreaua41a8b42005-12-17 14:02:24 +01008337 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008338 if (verbose)
8339 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8340 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008341 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008342 err |= ERR_RETRYABLE;
8343 pxerr |= 1;
8344 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008345 }
willy tarreau0f7af912005-12-17 12:21:26 +01008346
willy tarreau41310e72006-03-25 18:17:56 +01008347 /* the socket is ready */
8348 listener->fd = fd;
8349
willy tarreaua41a8b42005-12-17 14:02:24 +01008350 /* the function for the accept() event */
8351 fdtab[fd].read = &event_accept;
8352 fdtab[fd].write = NULL; /* never called */
8353 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01008354 fdtab[fd].state = FD_STLISTEN;
8355 FD_SET(fd, StaticReadEvent);
8356 fd_insert(fd);
8357 listeners++;
8358 }
willy tarreau41310e72006-03-25 18:17:56 +01008359
8360 if (!pxerr) {
8361 curproxy->state = PR_STRUN;
8362 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
8363 }
willy tarreau0f7af912005-12-17 12:21:26 +01008364 }
willy tarreau41310e72006-03-25 18:17:56 +01008365
8366 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01008367}
8368
willy tarreaub952e1d2005-12-18 01:31:20 +01008369int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008370
8371 appsess *temp1,*temp2;
8372 temp1 = (appsess *)key1;
8373 temp2 = (appsess *)key2;
8374
8375 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8376 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8377
8378 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8379}/* end match_str */
8380
willy tarreaub952e1d2005-12-18 01:31:20 +01008381void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008382 appsess *temp1;
8383
8384 //printf("destroy called\n");
8385 temp1 = (appsess *)data;
8386
8387 if (temp1->sessid)
8388 pool_free_to(apools.sessid, temp1->sessid);
8389
8390 if (temp1->serverid)
8391 pool_free_to(apools.serverid, temp1->serverid);
8392
8393 pool_free(appsess, temp1);
8394} /* end destroy */
8395
8396void appsession_cleanup( void )
8397{
8398 struct proxy *p = proxy;
8399
8400 while(p) {
8401 chtbl_destroy(&(p->htbl_proxy));
8402 p = p->next;
8403 }
8404}/* end appsession_cleanup() */
8405
8406void pool_destroy(void **pool)
8407{
8408 void *temp, *next;
8409 next = pool;
8410 while (next) {
8411 temp = next;
8412 next = *(void **)temp;
8413 free(temp);
8414 }
8415}/* end pool_destroy() */
8416
willy tarreaub952e1d2005-12-18 01:31:20 +01008417void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008418 struct proxy *p = proxy;
8419 struct cap_hdr *h,*h_next;
8420 struct server *s,*s_next;
8421 struct listener *l,*l_next;
8422
8423 while (p) {
8424 if (p->id)
8425 free(p->id);
8426
8427 if (p->check_req)
8428 free(p->check_req);
8429
8430 if (p->cookie_name)
8431 free(p->cookie_name);
8432
8433 if (p->capture_name)
8434 free(p->capture_name);
8435
8436 /* only strup if the user have set in config.
8437 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008438 if (p->errmsg.msg400) free(p->errmsg.msg400);
8439 if (p->errmsg.msg403) free(p->errmsg.msg403);
8440 if (p->errmsg.msg408) free(p->errmsg.msg408);
8441 if (p->errmsg.msg500) free(p->errmsg.msg500);
8442 if (p->errmsg.msg502) free(p->errmsg.msg502);
8443 if (p->errmsg.msg503) free(p->errmsg.msg503);
8444 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008445 */
8446 if (p->appsession_name)
8447 free(p->appsession_name);
8448
8449 h = p->req_cap;
8450 while (h) {
8451 h_next = h->next;
8452 if (h->name)
8453 free(h->name);
8454 pool_destroy(h->pool);
8455 free(h);
8456 h = h_next;
8457 }/* end while(h) */
8458
8459 h = p->rsp_cap;
8460 while (h) {
8461 h_next = h->next;
8462 if (h->name)
8463 free(h->name);
8464
8465 pool_destroy(h->pool);
8466 free(h);
8467 h = h_next;
8468 }/* end while(h) */
8469
8470 s = p->srv;
8471 while (s) {
8472 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008473 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008474 free(s->id);
8475
willy tarreaub952e1d2005-12-18 01:31:20 +01008476 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008477 free(s->cookie);
8478
8479 free(s);
8480 s = s_next;
8481 }/* end while(s) */
8482
8483 l = p->listen;
8484 while (l) {
8485 l_next = l->next;
8486 free(l);
8487 l = l_next;
8488 }/* end while(l) */
8489
8490 pool_destroy((void **) p->req_cap_pool);
8491 pool_destroy((void **) p->rsp_cap_pool);
8492 p = p->next;
8493 }/* end while(p) */
8494
8495 if (global.chroot) free(global.chroot);
8496 if (global.pidfile) free(global.pidfile);
8497
willy tarreau12350152005-12-18 01:03:27 +01008498 if (StaticReadEvent) free(StaticReadEvent);
8499 if (StaticWriteEvent) free(StaticWriteEvent);
8500 if (fdtab) free(fdtab);
8501
8502 pool_destroy(pool_session);
8503 pool_destroy(pool_buffer);
8504 pool_destroy(pool_fdtab);
8505 pool_destroy(pool_requri);
8506 pool_destroy(pool_task);
8507 pool_destroy(pool_capture);
8508 pool_destroy(pool_appsess);
8509
8510 if (have_appsession) {
8511 pool_destroy(apools.serverid);
8512 pool_destroy(apools.sessid);
8513 }
8514} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008515
willy tarreau41310e72006-03-25 18:17:56 +01008516/* sends the signal <sig> to all pids found in <oldpids> */
8517static void tell_old_pids(int sig) {
8518 int p;
8519 for (p = 0; p < nb_oldpids; p++)
8520 kill(oldpids[p], sig);
8521}
8522
willy tarreau0f7af912005-12-17 12:21:26 +01008523int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01008524 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01008525 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008526 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008527 init(argc, argv);
8528
willy tarreau0f7af912005-12-17 12:21:26 +01008529 signal(SIGQUIT, dump);
8530 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008531 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008532#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008533 signal(SIGINT, sig_int);
8534 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008535#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008536
8537 /* on very high loads, a sigpipe sometimes happen just between the
8538 * getsockopt() which tells "it's OK to write", and the following write :-(
8539 */
willy tarreau3242e862005-12-17 12:27:53 +01008540#ifndef MSG_NOSIGNAL
8541 signal(SIGPIPE, SIG_IGN);
8542#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008543
willy tarreau41310e72006-03-25 18:17:56 +01008544 /* We will loop at most 100 times with 10 ms delay each time.
8545 * That's at most 1 second. We only send a signal to old pids
8546 * if we cannot grab at least one port.
8547 */
8548 retry = MAX_START_RETRIES;
8549 err = ERR_NONE;
8550 while (retry >= 0) {
8551 struct timeval w;
8552 err = start_proxies(retry == 0 || nb_oldpids == 0);
8553 if (err != ERR_RETRYABLE)
8554 break;
8555 if (nb_oldpids == 0)
8556 break;
8557
8558 tell_old_pids(SIGTTOU);
8559 /* give some time to old processes to stop listening */
8560 w.tv_sec = 0;
8561 w.tv_usec = 10*1000;
8562 select(0, NULL, NULL, NULL, &w);
8563 retry--;
8564 }
8565
8566 /* Note: start_proxies() sends an alert when it fails. */
8567 if (err != ERR_NONE) {
8568 if (retry != MAX_START_RETRIES && nb_oldpids)
8569 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01008570 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01008571 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008572
8573 if (listeners == 0) {
8574 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008575 /* Note: we don't have to send anything to the old pids because we
8576 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01008577 exit(1);
8578 }
8579
willy tarreaudbd3bef2006-01-20 19:35:18 +01008580 /* prepare pause/play signals */
8581 signal(SIGTTOU, sig_pause);
8582 signal(SIGTTIN, sig_listen);
8583
Willy TARREAUe3283d12006-03-01 22:15:29 +01008584 if (global.mode & MODE_DAEMON) {
8585 global.mode &= ~MODE_VERBOSE;
8586 global.mode |= MODE_QUIET;
8587 }
8588
willy tarreaud0fb4652005-12-18 01:32:04 +01008589 /* MODE_QUIET can inhibit alerts and warnings below this line */
8590
8591 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008592 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008593 /* detach from the tty */
8594 fclose(stdin); fclose(stdout); fclose(stderr);
8595 close(0); close(1); close(2);
8596 }
willy tarreau0f7af912005-12-17 12:21:26 +01008597
willy tarreaufe2c5c12005-12-17 14:14:34 +01008598 /* open log & pid files before the chroot */
8599 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8600 int pidfd;
8601 unlink(global.pidfile);
8602 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8603 if (pidfd < 0) {
8604 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01008605 if (nb_oldpids)
8606 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01008607 exit(1);
8608 }
8609 pidfile = fdopen(pidfd, "w");
8610 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008611
8612 /* chroot if needed */
8613 if (global.chroot != NULL) {
8614 if (chroot(global.chroot) == -1) {
8615 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01008616 if (nb_oldpids)
8617 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01008618 }
8619 chdir("/");
8620 }
8621
willy tarreaub1285d52005-12-18 01:20:14 +01008622 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01008623 if (!global.rlimit_nofile)
8624 global.rlimit_nofile = global.maxsock;
8625
willy tarreaub1285d52005-12-18 01:20:14 +01008626 if (global.rlimit_nofile) {
8627 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8628 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8629 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8630 }
willy tarreau746e26b2006-03-25 11:14:35 +01008631 }
8632
8633 if (global.rlimit_memmax) {
8634 limit.rlim_cur = limit.rlim_max =
8635 global.rlimit_memmax * 1048576 / global.nbproc;
8636#ifdef RLIMIT_AS
8637 if (setrlimit(RLIMIT_AS, &limit) == -1) {
8638 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8639 argv[0], global.rlimit_memmax);
8640 }
8641#else
8642 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
8643 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8644 argv[0], global.rlimit_memmax);
8645 }
8646#endif
willy tarreaub1285d52005-12-18 01:20:14 +01008647 }
8648
willy tarreau41310e72006-03-25 18:17:56 +01008649 if (nb_oldpids)
8650 tell_old_pids(oldpids_sig);
8651
8652 /* Note that any error at this stage will be fatal because we will not
8653 * be able to restart the old pids.
8654 */
8655
willy tarreau9fe663a2005-12-17 13:02:59 +01008656 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008657 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008658 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8659 exit(1);
8660 }
8661
willy tarreau036e1ce2005-12-17 13:46:33 +01008662 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008663 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8664 exit(1);
8665 }
8666
willy tarreaub1285d52005-12-18 01:20:14 +01008667 /* check ulimits */
8668 limit.rlim_cur = limit.rlim_max = 0;
8669 getrlimit(RLIMIT_NOFILE, &limit);
8670 if (limit.rlim_cur < global.maxsock) {
8671 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",
8672 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8673 }
8674
willy tarreau9fe663a2005-12-17 13:02:59 +01008675 if (global.mode & MODE_DAEMON) {
8676 int ret = 0;
8677 int proc;
8678
8679 /* the father launches the required number of processes */
8680 for (proc = 0; proc < global.nbproc; proc++) {
8681 ret = fork();
8682 if (ret < 0) {
8683 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008684 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01008685 exit(1); /* there has been an error */
8686 }
8687 else if (ret == 0) /* child breaks here */
8688 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008689 if (pidfile != NULL) {
8690 fprintf(pidfile, "%d\n", ret);
8691 fflush(pidfile);
8692 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008693 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008694 /* close the pidfile both in children and father */
8695 if (pidfile != NULL)
8696 fclose(pidfile);
8697 free(global.pidfile);
8698
willy tarreau9fe663a2005-12-17 13:02:59 +01008699 if (proc == global.nbproc)
8700 exit(0); /* parent must leave */
8701
willy tarreau750a4722005-12-17 13:21:24 +01008702 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8703 * that we can detach from the TTY. We MUST NOT do it in other cases since
8704 * it would have already be done, and 0-2 would have been affected to listening
8705 * sockets
8706 */
8707 if (!(global.mode & MODE_QUIET)) {
8708 /* detach from the tty */
8709 fclose(stdin); fclose(stdout); fclose(stderr);
8710 close(0); close(1); close(2); /* close all fd's */
8711 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8712 }
willy tarreaua1598082005-12-17 13:08:06 +01008713 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008714 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008715 }
8716
willy tarreau1c2ad212005-12-18 01:11:29 +01008717#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008718 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008719 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8720 epoll_loop(POLL_LOOP_ACTION_RUN);
8721 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008722 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008723 }
8724 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008725 Warning("epoll() is not available. Using poll()/select() instead.\n");
8726 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008727 }
8728 }
8729#endif
8730
8731#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008732 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008733 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8734 poll_loop(POLL_LOOP_ACTION_RUN);
8735 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008736 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008737 }
8738 else {
8739 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008740 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008741 }
8742 }
8743#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008744 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008745 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8746 select_loop(POLL_LOOP_ACTION_RUN);
8747 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008748 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008749 }
8750 }
8751
willy tarreau0f7af912005-12-17 12:21:26 +01008752
willy tarreau12350152005-12-18 01:03:27 +01008753 /* Free all Hash Keys and all Hash elements */
8754 appsession_cleanup();
8755 /* Do some cleanup */
8756 deinit();
8757
willy tarreau0f7af912005-12-17 12:21:26 +01008758 exit(0);
8759}
willy tarreau12350152005-12-18 01:03:27 +01008760
8761#if defined(DEBUG_HASH)
8762static void print_table(const CHTbl *htbl) {
8763
8764 ListElmt *element;
8765 int i;
8766 appsess *asession;
8767
8768 /*****************************************************************************
8769 * *
8770 * Display the chained hash table. *
8771 * *
8772 *****************************************************************************/
8773
8774 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8775
8776 for (i = 0; i < TBLSIZ; i++) {
8777 fprintf(stdout, "Bucket[%03d]\n", i);
8778
8779 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8780 //fprintf(stdout, "%c", *(char *)list_data(element));
8781 asession = (appsess *)list_data(element);
8782 fprintf(stdout, "ELEM :%s:", asession->sessid);
8783 fprintf(stdout, " Server :%s: \n", asession->serverid);
8784 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8785 }
8786
8787 fprintf(stdout, "\n");
8788 }
8789 return;
8790} /* end print_table */
8791#endif
8792
8793static int appsession_init(void)
8794{
8795 static int initialized = 0;
8796 int idlen;
8797 struct server *s;
8798 struct proxy *p = proxy;
8799
8800 if (!initialized) {
8801 if (!appsession_task_init()) {
8802 apools.sessid = NULL;
8803 apools.serverid = NULL;
8804 apools.ser_waste = 0;
8805 apools.ser_use = 0;
8806 apools.ser_msize = sizeof(void *);
8807 apools.ses_waste = 0;
8808 apools.ses_use = 0;
8809 apools.ses_msize = sizeof(void *);
8810 while (p) {
8811 s = p->srv;
8812 if (apools.ses_msize < p->appsession_len)
8813 apools.ses_msize = p->appsession_len;
8814 while (s) {
8815 idlen = strlen(s->id);
8816 if (apools.ser_msize < idlen)
8817 apools.ser_msize = idlen;
8818 s = s->next;
8819 }
8820 p = p->next;
8821 }
8822 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8823 apools.ses_msize ++;
8824 }
8825 else {
8826 fprintf(stderr, "appsession_task_init failed\n");
8827 return -1;
8828 }
8829 initialized ++;
8830 }
8831 return 0;
8832}
8833
8834static int appsession_task_init(void)
8835{
8836 static int initialized = 0;
8837 struct task *t;
8838 if (!initialized) {
8839 if ((t = pool_alloc(task)) == NULL)
8840 return -1;
8841 t->next = t->prev = t->rqnext = NULL;
8842 t->wq = LIST_HEAD(wait_queue);
8843 t->state = TASK_IDLE;
8844 t->context = NULL;
8845 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8846 task_queue(t);
8847 t->process = appsession_refresh;
8848 initialized ++;
8849 }
8850 return 0;
8851}
8852
8853static int appsession_refresh(struct task *t) {
8854 struct proxy *p = proxy;
8855 CHTbl *htbl;
8856 ListElmt *element, *last;
8857 int i;
8858 appsess *asession;
8859 void *data;
8860
8861 while (p) {
8862 if (p->appsession_name != NULL) {
8863 htbl = &p->htbl_proxy;
8864 /* if we ever give up the use of TBLSIZ, we need to change this */
8865 for (i = 0; i < TBLSIZ; i++) {
8866 last = NULL;
8867 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8868 asession = (appsess *)list_data(element);
8869 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8870 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8871 int len;
8872 /*
8873 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8874 */
8875 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8876 asession->sessid, asession->serverid?asession->serverid:"(null)");
8877 write(1, trash, len);
8878 }
8879 /* delete the expired element from within the hash table */
8880 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8881 && (htbl->table[i].destroy != NULL)) {
8882 htbl->table[i].destroy(data);
8883 }
8884 if (last == NULL) {/* patient lost his head, get a new one */
8885 element = list_head(&htbl->table[i]);
8886 if (element == NULL) break; /* no heads left, go to next patient */
8887 }
8888 else
8889 element = last;
8890 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8891 else
8892 last = element;
8893 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8894 }
8895 }
8896 p = p->next;
8897 }
8898 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8899 return TBLCHKINT;
8900} /* end appsession_refresh */
8901