blob: 79d2185771817c2e37f6e0a337c7da031d76283d [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 tarreaud8b1fa52006-03-19 21:01:07 +010090#define HAPROXY_VERSION "1.2.10"
91#define HAPROXY_DATE "2006/03/19"
willy tarreau0f7af912005-12-17 12:21:26 +010092
93/* this is for libc5 for example */
94#ifndef TCP_NODELAY
95#define TCP_NODELAY 1
96#endif
97
98#ifndef SHUT_RD
99#define SHUT_RD 0
100#endif
101
102#ifndef SHUT_WR
103#define SHUT_WR 1
104#endif
105
willy tarreau0174f312005-12-18 01:02:42 +0100106/*
107 * BUFSIZE defines the size of a read and write buffer. It is the maximum
108 * amount of bytes which can be stored by the proxy for each session. However,
109 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
110 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
111 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
112 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
113 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
114 */
115#ifndef BUFSIZE
116#define BUFSIZE 16384
117#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100118
119// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100120#ifndef MAXREWRITE
121#define MAXREWRITE (BUFSIZE / 2)
122#endif
123
willy tarreau9fe663a2005-12-17 13:02:59 +0100124#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100125#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100126
willy tarreau5cbea6f2005-12-17 12:48:26 +0100127// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100128#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100129
willy tarreaue39cd132005-12-17 13:00:18 +0100130// max # of added headers per request
131#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100132
133// max # of matches per regexp
134#define MAX_MATCH 10
135
willy tarreau0174f312005-12-18 01:02:42 +0100136// cookie delimitor in "prefix" mode. This character is inserted between the
137// persistence cookie and the original value. The '~' is allowed by RFC2965,
138// and should not be too common in server names.
139#ifndef COOKIE_DELIM
140#define COOKIE_DELIM '~'
141#endif
142
willy tarreau0f7af912005-12-17 12:21:26 +0100143#define CONN_RETRIES 3
144
willy tarreau5cbea6f2005-12-17 12:48:26 +0100145#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100146#define DEF_CHKINTR 2000
147#define DEF_FALLTIME 3
148#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100149#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100150
Willy TARREAU13032e72006-03-12 17:31:45 +0100151/* Default connections limit.
152 *
153 * A system limit can be enforced at build time in order to avoid using haproxy
154 * beyond reasonable system limits. For this, just define SYSTEM_MAXCONN to the
155 * absolute limit accepted by the system. If the configuration specifies a
156 * higher value, it will be capped to SYSTEM_MAXCONN and a warning will be
157 * emitted. The only way to override this limit will be to set it via the
158 * command-line '-n' argument.
159 */
160#ifndef SYSTEM_MAXCONN
willy tarreau9fe663a2005-12-17 13:02:59 +0100161#define DEFAULT_MAXCONN 2000
Willy TARREAU13032e72006-03-12 17:31:45 +0100162#else
163#define DEFAULT_MAXCONN SYSTEM_MAXCONN
164#endif
willy tarreau9fe663a2005-12-17 13:02:59 +0100165
willy tarreau0f7af912005-12-17 12:21:26 +0100166/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
167#define INTBITS 5
168
169/* show stats this every millisecond, 0 to disable */
170#ifndef STATTIME
171#define STATTIME 2000
172#endif
173
willy tarreau5cbea6f2005-12-17 12:48:26 +0100174/* this reduces the number of calls to select() by choosing appropriate
175 * sheduler precision in milliseconds. It should be near the minimum
176 * time that is needed by select() to collect all events. All timeouts
177 * are rounded up by adding this value prior to pass it to select().
178 */
179#define SCHEDULER_RESOLUTION 9
180
willy tarreaub952e1d2005-12-18 01:31:20 +0100181#define TIME_ETERNITY -1
182/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100183#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
184#define SETNOW(a) (*a=now)
185
willy tarreau9da061b2005-12-17 12:29:56 +0100186/****** string-specific macros and functions ******/
187/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
188#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
189
190/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
191#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
192
willy tarreau0174f312005-12-18 01:02:42 +0100193/* returns 1 only if only zero or one bit is set in X, which means that X is a
194 * power of 2, and 0 otherwise */
195#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100196/*
197 * copies at most <size-1> chars from <src> to <dst>. Last char is always
198 * set to 0, unless <size> is 0. The number of chars copied is returned
199 * (excluding the terminating zero).
200 * This code has been optimized for size and speed : on x86, it's 45 bytes
201 * long, uses only registers, and consumes only 4 cycles per char.
202 */
willy tarreau750a4722005-12-17 13:21:24 +0100203int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100204 char *orig = dst;
205 if (size) {
206 while (--size && (*dst = *src)) {
207 src++; dst++;
208 }
209 *dst = 0;
210 }
211 return dst - orig;
212}
willy tarreau9da061b2005-12-17 12:29:56 +0100213
willy tarreau4302f492005-12-18 01:00:37 +0100214/*
215 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
216 * dynamically allocated. In the first case, <__pool> is updated to point to
217 * the next element in the list.
218 */
219#define pool_alloc_from(__pool, __len) ({ \
220 void *__p; \
221 if ((__p = (__pool)) == NULL) \
222 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
223 else { \
224 __pool = *(void **)(__pool); \
225 } \
226 __p; \
227})
228
229/*
230 * Puts a memory area back to the corresponding pool.
231 * Items are chained directly through a pointer that
232 * is written in the beginning of the memory area, so
233 * there's no need for any carrier cell. This implies
234 * that each memory area is at least as big as one
235 * pointer.
236 */
237#define pool_free_to(__pool, __ptr) ({ \
238 *(void **)(__ptr) = (void *)(__pool); \
239 __pool = (void *)(__ptr); \
240})
241
242
willy tarreau0f7af912005-12-17 12:21:26 +0100243#define MEM_OPTIM
244#ifdef MEM_OPTIM
245/*
246 * Returns a pointer to type <type> taken from the
247 * pool <pool_type> or dynamically allocated. In the
248 * first case, <pool_type> is updated to point to the
249 * next element in the list.
250 */
251#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100252 void *__p; \
253 if ((__p = pool_##type) == NULL) \
254 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100255 else { \
256 pool_##type = *(void **)pool_##type; \
257 } \
willy tarreau4302f492005-12-18 01:00:37 +0100258 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100259})
260
261/*
262 * Puts a memory area back to the corresponding pool.
263 * Items are chained directly through a pointer that
264 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100265 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100266 * that each memory area is at least as big as one
267 * pointer.
268 */
269#define pool_free(type, ptr) ({ \
270 *(void **)ptr = (void *)pool_##type; \
271 pool_##type = (void *)ptr; \
272})
273
274#else
275#define pool_alloc(type) (calloc(1,sizeof_##type));
276#define pool_free(type, ptr) (free(ptr));
277#endif /* MEM_OPTIM */
278
willy tarreau5cbea6f2005-12-17 12:48:26 +0100279#define sizeof_task sizeof(struct task)
280#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100281#define sizeof_buffer sizeof(struct buffer)
282#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100283#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100284#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100285#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100286#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100287
willy tarreau5cbea6f2005-12-17 12:48:26 +0100288/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100289#define FD_STCLOSE 0
290#define FD_STLISTEN 1
291#define FD_STCONN 2
292#define FD_STREADY 3
293#define FD_STERROR 4
294
willy tarreau5cbea6f2005-12-17 12:48:26 +0100295/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100296#define TASK_IDLE 0
297#define TASK_RUNNING 1
298
willy tarreau5cbea6f2005-12-17 12:48:26 +0100299/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100300#define PR_STNEW 0
301#define PR_STIDLE 1
302#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100303#define PR_STSTOPPED 3
304#define PR_STPAUSED 4
willy tarreau0f7af912005-12-17 12:21:26 +0100305
willy tarreau5cbea6f2005-12-17 12:48:26 +0100306/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100307#define PR_MODE_TCP 0
308#define PR_MODE_HTTP 1
309#define PR_MODE_HEALTH 2
310
willy tarreau1c2ad212005-12-18 01:11:29 +0100311/* possible actions for the *poll() loops */
312#define POLL_LOOP_ACTION_INIT 0
313#define POLL_LOOP_ACTION_RUN 1
314#define POLL_LOOP_ACTION_CLEAN 2
315
willy tarreau64a3cc32005-12-18 01:13:11 +0100316/* poll mechanisms available */
317#define POLL_USE_SELECT (1<<0)
318#define POLL_USE_POLL (1<<1)
319#define POLL_USE_EPOLL (1<<2)
320
willy tarreau5cbea6f2005-12-17 12:48:26 +0100321/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100322#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
323#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
324#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
325#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
326#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
327#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
328#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
329#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100330#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau0174f312005-12-18 01:02:42 +0100331#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
332#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
333#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
334#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
335#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
336#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
337#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
338#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
339#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
340#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
341#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100342#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
343#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100344#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100345#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100346
willy tarreaue39cd132005-12-17 13:00:18 +0100347/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100348#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
349#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
350#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
351#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
352#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
353#define SN_POST 0x00000020 /* the request was an HTTP POST */
willy tarreaub1285d52005-12-18 01:20:14 +0100354#define SN_MONITOR 0x00000040 /* this session comes from a monitoring system */
willy tarreau036e1ce2005-12-17 13:46:33 +0100355
356#define SN_CK_NONE 0x00000000 /* this session had no cookie */
357#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
358#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
359#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
360#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
361#define SN_CK_SHIFT 6 /* bit shift */
362
willy tarreaub1285d52005-12-18 01:20:14 +0100363#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100364#define SN_ERR_CLITO 0x00000100 /* client time-out */
365#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
366#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
367#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
368#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100369#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
370#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100371#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
372#define SN_ERR_SHIFT 8 /* bit shift */
373
374#define SN_FINST_R 0x00001000 /* session ended during client request */
375#define SN_FINST_C 0x00002000 /* session ended during server connect */
376#define SN_FINST_H 0x00003000 /* session ended during server headers */
377#define SN_FINST_D 0x00004000 /* session ended during data phase */
378#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
379#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
380#define SN_FINST_SHIFT 12 /* bit shift */
381
382#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
383#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
384#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
385#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
386#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100387#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100388#define SN_SCK_SHIFT 16 /* bit shift */
389
willy tarreau97f58572005-12-18 00:53:44 +0100390#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
391#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
392#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100393
394/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100395#define CL_STHEADERS 0
396#define CL_STDATA 1
397#define CL_STSHUTR 2
398#define CL_STSHUTW 3
399#define CL_STCLOSE 4
400
willy tarreau5cbea6f2005-12-17 12:48:26 +0100401/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100402#define SV_STIDLE 0
403#define SV_STCONN 1
404#define SV_STHEADERS 2
405#define SV_STDATA 3
406#define SV_STSHUTR 4
407#define SV_STSHUTW 5
408#define SV_STCLOSE 6
409
410/* result of an I/O event */
411#define RES_SILENT 0 /* didn't happen */
412#define RES_DATA 1 /* data were sent or received */
413#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
414#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
415
willy tarreau9fe663a2005-12-17 13:02:59 +0100416/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100417#define MODE_DEBUG 1
418#define MODE_STATS 2
419#define MODE_LOG 4
420#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100421#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100422#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100423#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100424#define MODE_STARTING 128
willy tarreau5cbea6f2005-12-17 12:48:26 +0100425
426/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100427#define SRV_RUNNING 1 /* the server is UP */
428#define SRV_BACKUP 2 /* this server is a backup server */
429#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100430#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100431#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100432
willy tarreaue39cd132005-12-17 13:00:18 +0100433/* what to do when a header matches a regex */
434#define ACT_ALLOW 0 /* allow the request */
435#define ACT_REPLACE 1 /* replace the matching header */
436#define ACT_REMOVE 2 /* remove the matching header */
437#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100438#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100439
willy tarreau9fe663a2005-12-17 13:02:59 +0100440/* configuration sections */
441#define CFG_NONE 0
442#define CFG_GLOBAL 1
443#define CFG_LISTEN 2
444
willy tarreaua1598082005-12-17 13:08:06 +0100445/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100446#define LW_DATE 1 /* date */
447#define LW_CLIP 2 /* CLient IP */
448#define LW_SVIP 4 /* SerVer IP */
449#define LW_SVID 8 /* server ID */
450#define LW_REQ 16 /* http REQuest */
451#define LW_RESP 32 /* http RESPonse */
452#define LW_PXIP 64 /* proxy IP */
453#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100454#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100455#define LW_COOKIE 512 /* captured cookie */
456#define LW_REQHDR 1024 /* request header(s) */
457#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100458
willy tarreau0f7af912005-12-17 12:21:26 +0100459/*********************************************************************/
460
461#define LIST_HEAD(a) ((void *)(&(a)))
462
463/*********************************************************************/
464
willy tarreau4302f492005-12-18 01:00:37 +0100465struct cap_hdr {
466 struct cap_hdr *next;
467 char *name; /* header name, case insensitive */
468 int namelen; /* length of the header name, to speed-up lookups */
469 int len; /* capture length, not including terminal zero */
470 int index; /* index in the output array */
471 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
472};
473
willy tarreau0f7af912005-12-17 12:21:26 +0100474struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100475 struct hdr_exp *next;
476 regex_t *preg; /* expression to look for */
477 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
478 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100479};
480
481struct buffer {
482 unsigned int l; /* data length */
483 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100484 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100485 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100486 char data[BUFSIZE];
487};
488
489struct server {
490 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100491 int state; /* server state (SRV_*) */
492 int cklen; /* the len of the cookie, to speed up checks */
493 char *cookie; /* the id set in the cookie */
494 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100495 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100496 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100497 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100498 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100499 int rise, fall; /* time in iterations */
500 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100501 int result; /* 0 = connect OK, -1 = connect KO */
502 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100503 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100504};
505
willy tarreau5cbea6f2005-12-17 12:48:26 +0100506/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100507struct task {
508 struct task *next, *prev; /* chaining ... */
509 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100510 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100511 int state; /* task state : IDLE or RUNNING */
512 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100513 int (*process)(struct task *t); /* the function which processes the task */
514 void *context; /* the task's context */
515};
516
517/* WARNING: if new fields are added, they must be initialized in event_accept() */
518struct session {
519 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100520 /* application specific below */
521 struct timeval crexpire; /* expiration date for a client read */
522 struct timeval cwexpire; /* expiration date for a client write */
523 struct timeval srexpire; /* expiration date for a server read */
524 struct timeval swexpire; /* expiration date for a server write */
525 struct timeval cnexpire; /* expiration date for a connect */
526 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
527 struct proxy *proxy; /* the proxy this socket belongs to */
528 int cli_fd; /* the client side fd */
529 int srv_fd; /* the server side fd */
530 int cli_state; /* state of the client side */
531 int srv_state; /* state of the server side */
532 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100533 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100534 struct buffer *req; /* request buffer */
535 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100536 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100537 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100538 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100539 char **req_cap; /* array of captured request headers (may be NULL) */
540 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100541 struct {
542 int logwait; /* log fields waiting to be collected : LW_* */
543 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
544 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
545 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
546 long t_data; /* delay before the first data byte from the server ... */
547 unsigned long t_close; /* total session duration */
548 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100549 char *cli_cookie; /* cookie presented by the client, in capture mode */
550 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100551 int status; /* HTTP status from the server, negative if from proxy */
552 long long bytes; /* number of bytes transferred from the server */
553 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100554 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100555};
556
willy tarreaua41a8b42005-12-17 14:02:24 +0100557struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100558 int fd; /* the listen socket */
559 struct sockaddr_storage addr; /* the address we listen to */
560 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100561};
562
563
willy tarreau0f7af912005-12-17 12:21:26 +0100564struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100565 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100566 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 +0100567 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100568 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100569 struct server *srv, *cursrv; /* known servers, current server */
570 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100571 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100572 int cookie_len; /* strlen(cookie_name), computed only once */
573 char *appsession_name; /* name of the cookie to look for */
574 int appsession_name_len; /* strlen(appsession_name), computed only once */
575 int appsession_len; /* length of the appsession cookie value to be used */
576 int appsession_timeout;
577 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100578 char *capture_name; /* beginning of the name of the cookie to capture */
579 int capture_namelen; /* length of the cookie name to match */
580 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100581 int clitimeout; /* client I/O timeout (in milliseconds) */
582 int srvtimeout; /* server I/O timeout (in milliseconds) */
583 int contimeout; /* connect timeout (in milliseconds) */
584 char *id; /* proxy id */
585 int nbconn; /* # of active sessions */
586 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100587 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100588 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100589 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100590 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100591 struct proxy *next;
592 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100593 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100594 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100595 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100596 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100597 int nb_reqadd, nb_rspadd;
598 struct hdr_exp *req_exp; /* regular expressions for request headers */
599 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100600 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
601 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
602 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
603 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100604 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100605 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100606 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
607 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100608 struct {
609 char *msg400; /* message for error 400 */
610 int len400; /* message length for error 400 */
611 char *msg403; /* message for error 403 */
612 int len403; /* message length for error 403 */
613 char *msg408; /* message for error 408 */
614 int len408; /* message length for error 408 */
615 char *msg500; /* message for error 500 */
616 int len500; /* message length for error 500 */
617 char *msg502; /* message for error 502 */
618 int len502; /* message length for error 502 */
619 char *msg503; /* message for error 503 */
620 int len503; /* message length for error 503 */
621 char *msg504; /* message for error 504 */
622 int len504; /* message length for error 504 */
623 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100624};
625
626/* info about one given fd */
627struct fdtab {
628 int (*read)(int fd); /* read function */
629 int (*write)(int fd); /* write function */
630 struct task *owner; /* the session (or proxy) associated with this fd */
631 int state; /* the state of this fd */
632};
633
634/*********************************************************************/
635
willy tarreaub952e1d2005-12-18 01:31:20 +0100636int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100637int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100638char *cfg_cfgfile = NULL; /* configuration file */
639char *progname = NULL; /* program name */
640int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100641
642/* global options */
643static struct {
644 int uid;
645 int gid;
646 int nbproc;
647 int maxconn;
648 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100649 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100650 int mode;
651 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100652 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100653 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100654 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100655 struct sockaddr_in logsrv1, logsrv2;
656} global = {
657 logfac1 : -1,
658 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100659 loglev1 : 7, /* max syslog level : debug */
660 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100661 /* others NULL OK */
662};
663
willy tarreau0f7af912005-12-17 12:21:26 +0100664/*********************************************************************/
665
willy tarreau1c2ad212005-12-18 01:11:29 +0100666fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100667 *StaticWriteEvent;
668
willy tarreau64a3cc32005-12-18 01:13:11 +0100669int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100670
willy tarreau0f7af912005-12-17 12:21:26 +0100671void **pool_session = NULL,
672 **pool_buffer = NULL,
673 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100674 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100675 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100676 **pool_capture = NULL,
677 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100678
679struct proxy *proxy = NULL; /* list of all existing proxies */
680struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100681struct task *rq = NULL; /* global run queue */
682struct task wait_queue = { /* global wait queue */
683 prev:LIST_HEAD(wait_queue),
684 next:LIST_HEAD(wait_queue)
685};
willy tarreau0f7af912005-12-17 12:21:26 +0100686
willy tarreau0f7af912005-12-17 12:21:26 +0100687static int totalconn = 0; /* total # of terminated sessions */
688static int actconn = 0; /* # of active sessions */
689static int maxfd = 0; /* # of the highest fd + 1 */
690static int listeners = 0; /* # of listeners */
691static int stopping = 0; /* non zero means stopping in progress */
692static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100693static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100694
willy tarreau08dedbe2005-12-18 01:13:48 +0100695#if defined(ENABLE_EPOLL)
696/* FIXME: this is dirty, but at the moment, there's no other solution to remove
697 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
698 * structure with pointers to functions such as init_fd() and close_fd(), plus
699 * a private structure with several pointers to places such as below.
700 */
701
702static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
703#endif
704
willy tarreau0f7af912005-12-17 12:21:26 +0100705static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100706/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100707static char trash[BUFSIZE];
708
willy tarreaudd07e972005-12-18 00:48:48 +0100709const int zero = 0;
710const int one = 1;
711
willy tarreau0f7af912005-12-17 12:21:26 +0100712/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100713 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100714 */
715
716#define MAX_SYSLOG_LEN 1024
717#define NB_LOG_FACILITIES 24
718const char *log_facilities[NB_LOG_FACILITIES] = {
719 "kern", "user", "mail", "daemon",
720 "auth", "syslog", "lpr", "news",
721 "uucp", "cron", "auth2", "ftp",
722 "ntp", "audit", "alert", "cron2",
723 "local0", "local1", "local2", "local3",
724 "local4", "local5", "local6", "local7"
725};
726
727
728#define NB_LOG_LEVELS 8
729const char *log_levels[NB_LOG_LEVELS] = {
730 "emerg", "alert", "crit", "err",
731 "warning", "notice", "info", "debug"
732};
733
734#define SYSLOG_PORT 514
735
736const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
737 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100738
willy tarreaub1285d52005-12-18 01:20:14 +0100739const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100740const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
741const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
742const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
743 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
744 unknown, Set-cookie Rewritten */
745
willy tarreau0f7af912005-12-17 12:21:26 +0100746#define MAX_HOSTNAME_LEN 32
747static char hostname[MAX_HOSTNAME_LEN] = "";
748
willy tarreau8337c6b2005-12-17 13:41:01 +0100749const char *HTTP_302 =
750 "HTTP/1.0 302 Found\r\n"
751 "Cache-Control: no-cache\r\n"
752 "Connection: close\r\n"
753 "Location: "; /* not terminated since it will be concatenated with the URL */
754
willy tarreauc1f47532005-12-18 01:08:26 +0100755/* same as 302 except that the browser MUST retry with the GET method */
756const char *HTTP_303 =
757 "HTTP/1.0 303 See Other\r\n"
758 "Cache-Control: no-cache\r\n"
759 "Connection: close\r\n"
760 "Location: "; /* not terminated since it will be concatenated with the URL */
761
willy tarreaua1598082005-12-17 13:08:06 +0100762const char *HTTP_400 =
763 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100764 "Cache-Control: no-cache\r\n"
765 "Connection: close\r\n"
766 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100767 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100768
willy tarreaua1598082005-12-17 13:08:06 +0100769const char *HTTP_403 =
770 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100771 "Cache-Control: no-cache\r\n"
772 "Connection: close\r\n"
773 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100774 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
775
willy tarreau8337c6b2005-12-17 13:41:01 +0100776const char *HTTP_408 =
777 "HTTP/1.0 408 Request Time-out\r\n"
778 "Cache-Control: no-cache\r\n"
779 "Connection: close\r\n"
780 "\r\n"
781 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
782
willy tarreau750a4722005-12-17 13:21:24 +0100783const char *HTTP_500 =
784 "HTTP/1.0 500 Server Error\r\n"
785 "Cache-Control: no-cache\r\n"
786 "Connection: close\r\n"
787 "\r\n"
788 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100789
790const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100791 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100792 "Cache-Control: no-cache\r\n"
793 "Connection: close\r\n"
794 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100795 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
796
797const char *HTTP_503 =
798 "HTTP/1.0 503 Service Unavailable\r\n"
799 "Cache-Control: no-cache\r\n"
800 "Connection: close\r\n"
801 "\r\n"
802 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
803
804const char *HTTP_504 =
805 "HTTP/1.0 504 Gateway Time-out\r\n"
806 "Cache-Control: no-cache\r\n"
807 "Connection: close\r\n"
808 "\r\n"
809 "<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 +0100810
willy tarreau0f7af912005-12-17 12:21:26 +0100811/*********************************************************************/
812/* statistics ******************************************************/
813/*********************************************************************/
814
willy tarreau750a4722005-12-17 13:21:24 +0100815#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100816static int stats_tsk_lsrch, stats_tsk_rsrch,
817 stats_tsk_good, stats_tsk_right, stats_tsk_left,
818 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100819#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100820
821
822/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100823/* debugging *******************************************************/
824/*********************************************************************/
825#ifdef DEBUG_FULL
826static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
827static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
828#endif
829
830/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100831/* function prototypes *********************************************/
832/*********************************************************************/
833
834int event_accept(int fd);
835int event_cli_read(int fd);
836int event_cli_write(int fd);
837int event_srv_read(int fd);
838int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100839int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100840
willy tarreau12350152005-12-18 01:03:27 +0100841static int appsession_task_init(void);
842static int appsession_init(void);
843static int appsession_refresh(struct task *t);
844
willy tarreau0f7af912005-12-17 12:21:26 +0100845/*********************************************************************/
846/* general purpose functions ***************************************/
847/*********************************************************************/
848
849void display_version() {
850 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100851 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100852}
853
854/*
855 * This function prints the command line usage and exits
856 */
857void usage(char *name) {
858 display_version();
859 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100860 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100861#if STATTIME > 0
862 "sl"
863#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100864 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100865 " -v displays version\n"
866 " -d enters debug mode\n"
willy tarreau982249e2005-12-18 00:57:06 +0100867 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100868#if STATTIME > 0
869 " -s enables statistics output\n"
870 " -l enables long statistics format\n"
871#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100872 " -D goes daemon ; implies -q\n"
873 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100874 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100875 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100876 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100877 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100878#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100879 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100880#endif
881#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100882 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100883#endif
willy tarreauad90a0c2005-12-18 01:09:15 +0100884 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100885 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100886 exit(1);
887}
888
889
890/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100891 * Displays the message on stderr with the date and pid. Overrides the quiet
892 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100893 */
894void Alert(char *fmt, ...) {
895 va_list argp;
896 struct timeval tv;
897 struct tm *tm;
898
willy tarreaud0fb4652005-12-18 01:32:04 +0100899 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100900 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100901
willy tarreau5cbea6f2005-12-17 12:48:26 +0100902 gettimeofday(&tv, NULL);
903 tm=localtime(&tv.tv_sec);
904 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100905 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100906 vfprintf(stderr, fmt, argp);
907 fflush(stderr);
908 va_end(argp);
909 }
willy tarreau0f7af912005-12-17 12:21:26 +0100910}
911
912
913/*
914 * Displays the message on stderr with the date and pid.
915 */
916void Warning(char *fmt, ...) {
917 va_list argp;
918 struct timeval tv;
919 struct tm *tm;
920
willy tarreau982249e2005-12-18 00:57:06 +0100921 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100922 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100923
willy tarreau5cbea6f2005-12-17 12:48:26 +0100924 gettimeofday(&tv, NULL);
925 tm=localtime(&tv.tv_sec);
926 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100927 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100928 vfprintf(stderr, fmt, argp);
929 fflush(stderr);
930 va_end(argp);
931 }
932}
933
934/*
935 * Displays the message on <out> only if quiet mode is not set.
936 */
937void qfprintf(FILE *out, char *fmt, ...) {
938 va_list argp;
939
willy tarreau982249e2005-12-18 00:57:06 +0100940 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100941 va_start(argp, fmt);
942 vfprintf(out, fmt, argp);
943 fflush(out);
944 va_end(argp);
945 }
willy tarreau0f7af912005-12-17 12:21:26 +0100946}
947
948
949/*
950 * converts <str> to a struct sockaddr_in* which is locally allocated.
951 * The format is "addr:port", where "addr" can be empty or "*" to indicate
952 * INADDR_ANY.
953 */
954struct sockaddr_in *str2sa(char *str) {
955 static struct sockaddr_in sa;
956 char *c;
957 int port;
958
willy tarreaua1598082005-12-17 13:08:06 +0100959 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100960 str=strdup(str);
961
962 if ((c=strrchr(str,':')) != NULL) {
963 *c++=0;
964 port=atol(c);
965 }
966 else
967 port=0;
968
969 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
970 sa.sin_addr.s_addr = INADDR_ANY;
971 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100972 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100973 struct hostent *he;
974
975 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100976 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100977 }
978 else
979 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
980 }
981 sa.sin_port=htons(port);
982 sa.sin_family=AF_INET;
983
984 free(str);
985 return &sa;
986}
987
willy tarreaub1285d52005-12-18 01:20:14 +0100988/*
989 * converts <str> to a two struct in_addr* which are locally allocated.
990 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
991 * is optionnal and either in the dotted or CIDR notation.
992 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
993 */
994int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
995 char *c;
996 unsigned long len;
997
998 memset(mask, 0, sizeof(*mask));
999 memset(addr, 0, sizeof(*addr));
1000 str=strdup(str);
1001
1002 if ((c = strrchr(str, '/')) != NULL) {
1003 *c++ = 0;
1004 /* c points to the mask */
1005 if (strchr(c, '.') != NULL) { /* dotted notation */
1006 if (!inet_pton(AF_INET, c, mask))
1007 return 0;
1008 }
1009 else { /* mask length */
1010 char *err;
1011 len = strtol(c, &err, 10);
1012 if (!*c || (err && *err) || (unsigned)len > 32)
1013 return 0;
1014 if (len)
1015 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1016 else
1017 mask->s_addr = 0;
1018 }
1019 }
1020 else {
1021 mask->s_addr = 0xFFFFFFFF;
1022 }
1023 if (!inet_pton(AF_INET, str, addr)) {
1024 struct hostent *he;
1025
1026 if ((he = gethostbyname(str)) == NULL) {
1027 return 0;
1028 }
1029 else
1030 *addr = *(struct in_addr *) *(he->h_addr_list);
1031 }
1032 free(str);
1033 return 1;
1034}
1035
willy tarreau9fe663a2005-12-17 13:02:59 +01001036
1037/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001038 * converts <str> to a list of listeners which are dynamically allocated.
1039 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1040 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1041 * - <port> is a numerical port from 1 to 65535 ;
1042 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1043 * This can be repeated as many times as necessary, separated by a coma.
1044 * The <tail> argument is a pointer to a current list which should be appended
1045 * to the tail of the new list. The pointer to the new list is returned.
1046 */
1047struct listener *str2listener(char *str, struct listener *tail) {
1048 struct listener *l;
1049 char *c, *next, *range, *dupstr;
1050 int port, end;
1051
1052 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001053
willy tarreaua41a8b42005-12-17 14:02:24 +01001054 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001055 struct sockaddr_storage ss;
1056
willy tarreaua41a8b42005-12-17 14:02:24 +01001057 str = next;
1058 /* 1) look for the end of the first address */
1059 if ((next = strrchr(str, ',')) != NULL) {
1060 *next++ = 0;
1061 }
1062
willy tarreau8a86dbf2005-12-18 00:45:59 +01001063 /* 2) look for the addr/port delimiter, it's the last colon. */
1064 if ((range = strrchr(str, ':')) == NULL) {
1065 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001066 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001067 }
1068
1069 *range++ = 0;
1070
1071 if (strrchr(str, ':') != NULL) {
1072 /* IPv6 address contains ':' */
1073 memset(&ss, 0, sizeof(ss));
1074 ss.ss_family = AF_INET6;
1075
1076 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1077 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001078 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001079 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001080 }
1081 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001082 memset(&ss, 0, sizeof(ss));
1083 ss.ss_family = AF_INET;
1084
1085 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1086 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1087 }
1088 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1089 struct hostent *he;
1090
1091 if ((he = gethostbyname(str)) == NULL) {
1092 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001093 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001094 }
1095 else
1096 ((struct sockaddr_in *)&ss)->sin_addr =
1097 *(struct in_addr *) *(he->h_addr_list);
1098 }
1099 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001100
1101 /* 3) look for the port-end delimiter */
1102 if ((c = strchr(range, '-')) != NULL) {
1103 *c++ = 0;
1104 end = atol(c);
1105 }
1106 else {
1107 end = atol(range);
1108 }
1109
willy tarreaud0fb4652005-12-18 01:32:04 +01001110 port = atol(range);
1111
1112 if (port < 1 || port > 65535) {
1113 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1114 goto fail;
1115 }
1116
1117 if (end < 1 || end > 65535) {
1118 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1119 goto fail;
1120 }
1121
1122 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001123 l = (struct listener *)calloc(1, sizeof(struct listener));
1124 l->next = tail;
1125 tail = l;
1126
willy tarreau8a86dbf2005-12-18 00:45:59 +01001127 l->addr = ss;
1128 if (ss.ss_family == AF_INET6)
1129 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1130 else
1131 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1132
willy tarreaua41a8b42005-12-17 14:02:24 +01001133 } /* end for(port) */
1134 } /* end while(next) */
1135 free(dupstr);
1136 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001137 fail:
1138 free(dupstr);
1139 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001140}
1141
willy tarreau4302f492005-12-18 01:00:37 +01001142
1143#define FD_SETS_ARE_BITFIELDS
1144#ifdef FD_SETS_ARE_BITFIELDS
1145/*
1146 * This map is used with all the FD_* macros to check whether a particular bit
1147 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1148 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1149 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1150 * exclusively to the macros.
1151 */
1152fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1153fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1154
1155#else
1156#error "Check if your OS uses bitfields for fd_sets"
1157#endif
1158
1159/* will try to encode the string <string> replacing all characters tagged in
1160 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1161 * prefixed by <escape>, and will store the result between <start> (included
1162 *) and <stop> (excluded), and will always terminate the string with a '\0'
1163 * before <stop>. The position of the '\0' is returned if the conversion
1164 * completes. If bytes are missing between <start> and <stop>, then the
1165 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1166 * cannot even be stored so we return <start> without writing the 0.
1167 * The input string must also be zero-terminated.
1168 */
1169char hextab[16] = "0123456789ABCDEF";
1170char *encode_string(char *start, char *stop,
1171 const char escape, const fd_set *map,
1172 const char *string)
1173{
1174 if (start < stop) {
1175 stop--; /* reserve one byte for the final '\0' */
1176 while (start < stop && *string != 0) {
1177 if (!FD_ISSET((unsigned char)(*string), map))
1178 *start++ = *string;
1179 else {
1180 if (start + 3 >= stop)
1181 break;
1182 *start++ = escape;
1183 *start++ = hextab[(*string >> 4) & 15];
1184 *start++ = hextab[*string & 15];
1185 }
1186 string++;
1187 }
1188 *start = '\0';
1189 }
1190 return start;
1191}
willy tarreaua41a8b42005-12-17 14:02:24 +01001192
1193/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001194 * This function sends a syslog message to both log servers of a proxy,
1195 * or to global log servers if the proxy is NULL.
1196 * It also tries not to waste too much time computing the message header.
1197 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001198 */
1199void send_log(struct proxy *p, int level, char *message, ...) {
1200 static int logfd = -1; /* syslog UDP socket */
1201 static long tvsec = -1; /* to force the string to be initialized */
1202 struct timeval tv;
1203 va_list argp;
1204 static char logmsg[MAX_SYSLOG_LEN];
1205 static char *dataptr = NULL;
1206 int fac_level;
1207 int hdr_len, data_len;
1208 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001209 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001210 int nbloggers = 0;
1211 char *log_ptr;
1212
1213 if (logfd < 0) {
1214 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1215 return;
1216 }
1217
1218 if (level < 0 || progname == NULL || message == NULL)
1219 return;
1220
1221 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001222 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001223 /* this string is rebuild only once a second */
1224 struct tm *tm = localtime(&tv.tv_sec);
1225 tvsec = tv.tv_sec;
1226
willy tarreauc29948c2005-12-17 13:10:27 +01001227 hdr_len = snprintf(logmsg, sizeof(logmsg),
1228 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1229 monthname[tm->tm_mon],
1230 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1231 progname, pid);
1232 /* WARNING: depending upon implementations, snprintf may return
1233 * either -1 or the number of bytes that would be needed to store
1234 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001235 */
willy tarreauc29948c2005-12-17 13:10:27 +01001236 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1237 hdr_len = sizeof(logmsg);
1238
1239 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001240 }
1241
1242 va_start(argp, message);
1243 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001244 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1245 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001246 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001247 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001248
1249 if (p == NULL) {
1250 if (global.logfac1 >= 0) {
1251 sa[nbloggers] = &global.logsrv1;
1252 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001253 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001254 nbloggers++;
1255 }
1256 if (global.logfac2 >= 0) {
1257 sa[nbloggers] = &global.logsrv2;
1258 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001259 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001260 nbloggers++;
1261 }
1262 } else {
1263 if (p->logfac1 >= 0) {
1264 sa[nbloggers] = &p->logsrv1;
1265 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001266 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001267 nbloggers++;
1268 }
1269 if (p->logfac2 >= 0) {
1270 sa[nbloggers] = &p->logsrv2;
1271 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001272 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001273 nbloggers++;
1274 }
1275 }
1276
1277 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001278 /* we can filter the level of the messages that are sent to each logger */
1279 if (level > loglevel[nbloggers])
1280 continue;
1281
willy tarreauc29948c2005-12-17 13:10:27 +01001282 /* For each target, we may have a different facility.
1283 * We can also have a different log level for each message.
1284 * This induces variations in the message header length.
1285 * Since we don't want to recompute it each time, nor copy it every
1286 * time, we only change the facility in the pre-computed header,
1287 * and we change the pointer to the header accordingly.
1288 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001289 fac_level = (facilities[nbloggers] << 3) + level;
1290 log_ptr = logmsg + 3; /* last digit of the log level */
1291 do {
1292 *log_ptr = '0' + fac_level % 10;
1293 fac_level /= 10;
1294 log_ptr--;
1295 } while (fac_level && log_ptr > logmsg);
1296 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001297
willy tarreauc29948c2005-12-17 13:10:27 +01001298 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001299
1300#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001301 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001302 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1303#else
willy tarreauc29948c2005-12-17 13:10:27 +01001304 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001305 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1306#endif
1307 }
willy tarreau0f7af912005-12-17 12:21:26 +01001308}
1309
1310
1311/* sets <tv> to the current time */
1312static inline struct timeval *tv_now(struct timeval *tv) {
1313 if (tv)
1314 gettimeofday(tv, NULL);
1315 return tv;
1316}
1317
1318/*
1319 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1320 */
1321static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1322 if (!tv || !from)
1323 return NULL;
1324 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1325 tv->tv_sec = from->tv_sec + (ms/1000);
1326 while (tv->tv_usec >= 1000000) {
1327 tv->tv_usec -= 1000000;
1328 tv->tv_sec++;
1329 }
1330 return tv;
1331}
1332
1333/*
1334 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001335 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001336 */
1337static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001338 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001339 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001340 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001341 return 1;
1342 else if (tv1->tv_usec < tv2->tv_usec)
1343 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001344 else if (tv1->tv_usec > tv2->tv_usec)
1345 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001346 else
1347 return 0;
1348}
1349
1350/*
1351 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001352 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001353 */
1354unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1355 int cmp;
1356 unsigned long ret;
1357
1358
willy tarreauef900ab2005-12-17 12:52:52 +01001359 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001360 if (!cmp)
1361 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001362 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001363 struct timeval *tmp = tv1;
1364 tv1 = tv2;
1365 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001366 }
willy tarreauef900ab2005-12-17 12:52:52 +01001367 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001368 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001369 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001370 else
willy tarreauef900ab2005-12-17 12:52:52 +01001371 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001372 return (unsigned long) ret;
1373}
1374
1375/*
willy tarreau750a4722005-12-17 13:21:24 +01001376 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001377 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001378 */
1379static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1380 unsigned long ret;
1381
willy tarreau6e682ce2005-12-17 13:26:49 +01001382 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1383 if (tv2->tv_usec > tv1->tv_usec)
1384 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001385 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001386 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001387 return (unsigned long) ret;
1388}
1389
1390/*
willy tarreau0f7af912005-12-17 12:21:26 +01001391 * 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 +01001392 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001393 */
1394static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001395 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001396 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001397 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001398 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001399 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001400 else
1401 return 0;
1402 }
willy tarreau0f7af912005-12-17 12:21:26 +01001403 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001404 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001405 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001406 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001407 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001408 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001409 else
1410 return 0;
1411}
1412
1413/*
1414 * returns the remaining time between tv1=now and event=tv2
1415 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001416 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001417 */
1418static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1419 unsigned long ret;
1420
willy tarreau0f7af912005-12-17 12:21:26 +01001421 if (tv_cmp_ms(tv1, tv2) >= 0)
1422 return 0; /* event elapsed */
1423
willy tarreauef900ab2005-12-17 12:52:52 +01001424 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001425 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001426 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001427 else
willy tarreauef900ab2005-12-17 12:52:52 +01001428 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001429 return (unsigned long) ret;
1430}
1431
1432
1433/*
1434 * zeroes a struct timeval
1435 */
1436
1437static inline struct timeval *tv_eternity(struct timeval *tv) {
1438 tv->tv_sec = tv->tv_usec = 0;
1439 return tv;
1440}
1441
1442/*
1443 * returns 1 if tv is null, else 0
1444 */
1445static inline int tv_iseternity(struct timeval *tv) {
1446 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1447 return 1;
1448 else
1449 return 0;
1450}
1451
1452/*
1453 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1454 * considering that 0 is the eternity.
1455 */
1456static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1457 if (tv_iseternity(tv1))
1458 if (tv_iseternity(tv2))
1459 return 0; /* same */
1460 else
1461 return 1; /* tv1 later than tv2 */
1462 else if (tv_iseternity(tv2))
1463 return -1; /* tv2 later than tv1 */
1464
1465 if (tv1->tv_sec > tv2->tv_sec)
1466 return 1;
1467 else if (tv1->tv_sec < tv2->tv_sec)
1468 return -1;
1469 else if (tv1->tv_usec > tv2->tv_usec)
1470 return 1;
1471 else if (tv1->tv_usec < tv2->tv_usec)
1472 return -1;
1473 else
1474 return 0;
1475}
1476
1477/*
1478 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1479 * considering that 0 is the eternity.
1480 */
1481static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1482 if (tv_iseternity(tv1))
1483 if (tv_iseternity(tv2))
1484 return 0; /* same */
1485 else
1486 return 1; /* tv1 later than tv2 */
1487 else if (tv_iseternity(tv2))
1488 return -1; /* tv2 later than tv1 */
1489
willy tarreauefae1842005-12-17 12:51:03 +01001490 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001491 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001492 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001493 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001494 return -1;
1495 else
1496 return 0;
1497 }
1498 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001499 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001500 return 1;
1501 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001502 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001503 return -1;
1504 else
1505 return 0;
1506}
1507
1508/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001509 * returns the remaining time between tv1=now and event=tv2
1510 * if tv2 is passed, 0 is returned.
1511 * Returns TIME_ETERNITY if tv2 is eternity.
1512 */
1513static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1514 unsigned long ret;
1515
1516 if (tv_iseternity(tv2))
1517 return TIME_ETERNITY;
1518
1519 if (tv_cmp_ms(tv1, tv2) >= 0)
1520 return 0; /* event elapsed */
1521
1522 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1523 if (tv2->tv_usec > tv1->tv_usec)
1524 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1525 else
1526 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1527 return (unsigned long) ret;
1528}
1529
1530/*
willy tarreau0f7af912005-12-17 12:21:26 +01001531 * returns the first event between tv1 and tv2 into tvmin.
1532 * a zero tv is ignored. tvmin is returned.
1533 */
1534static inline struct timeval *tv_min(struct timeval *tvmin,
1535 struct timeval *tv1, struct timeval *tv2) {
1536
1537 if (tv_cmp2(tv1, tv2) <= 0)
1538 *tvmin = *tv1;
1539 else
1540 *tvmin = *tv2;
1541
1542 return tvmin;
1543}
1544
1545
1546
1547/***********************************************************/
1548/* fd management ***************************************/
1549/***********************************************************/
1550
1551
1552
willy tarreau5cbea6f2005-12-17 12:48:26 +01001553/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1554 * The file descriptor is also closed.
1555 */
willy tarreau0f7af912005-12-17 12:21:26 +01001556static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001557 FD_CLR(fd, StaticReadEvent);
1558 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001559#if defined(ENABLE_EPOLL)
1560 if (PrevReadEvent) {
1561 FD_CLR(fd, PrevReadEvent);
1562 FD_CLR(fd, PrevWriteEvent);
1563 }
1564#endif
1565
willy tarreau5cbea6f2005-12-17 12:48:26 +01001566 close(fd);
1567 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001568
1569 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1570 maxfd--;
1571}
1572
1573/* recomputes the maxfd limit from the fd */
1574static inline void fd_insert(int fd) {
1575 if (fd+1 > maxfd)
1576 maxfd = fd+1;
1577}
1578
1579/*************************************************************/
1580/* task management ***************************************/
1581/*************************************************************/
1582
willy tarreau5cbea6f2005-12-17 12:48:26 +01001583/* puts the task <t> in run queue <q>, and returns <t> */
1584static inline struct task *task_wakeup(struct task **q, struct task *t) {
1585 if (t->state == TASK_RUNNING)
1586 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001587 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001588 t->rqnext = *q;
1589 t->state = TASK_RUNNING;
1590 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001591 }
1592}
1593
willy tarreau5cbea6f2005-12-17 12:48:26 +01001594/* removes the task <t> from the queue <q>
1595 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001596 * set the run queue to point to the next one, and return it
1597 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001598static inline struct task *task_sleep(struct task **q, struct task *t) {
1599 if (t->state == TASK_RUNNING) {
1600 *q = t->rqnext;
1601 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001602 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001603 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001604}
1605
1606/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001607 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001608 * from the run queue. A pointer to the task itself is returned.
1609 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001610static inline struct task *task_delete(struct task *t) {
1611 t->prev->next = t->next;
1612 t->next->prev = t->prev;
1613 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001614}
1615
1616/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001617 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001618 */
1619static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001620 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001621}
1622
willy tarreau5cbea6f2005-12-17 12:48:26 +01001623/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001624 * may be only moved or left where it was, depending on its timing requirements.
1625 * <task> is returned.
1626 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001627struct task *task_queue(struct task *task) {
1628 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001629 struct task *start_from;
1630
1631 /* first, test if the task was already in a list */
1632 if (task->prev == NULL) {
1633 // start_from = list;
1634 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001635#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001636 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001637#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001638 /* insert the unlinked <task> into the list, searching back from the last entry */
1639 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1640 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001641#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001642 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001643#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001644 }
1645
1646 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1647 // start_from = start_from->next;
1648 // stats_tsk_nsrch++;
1649 // }
1650 }
1651 else if (task->prev == list ||
1652 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1653 start_from = task->next;
1654 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001655#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001656 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001657#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001658 return task; /* it's already in the right place */
1659 }
1660
willy tarreau750a4722005-12-17 13:21:24 +01001661#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001662 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001663#endif
1664
1665 /* if the task is not at the right place, there's little chance that
1666 * it has only shifted a bit, and it will nearly always be queued
1667 * at the end of the list because of constant timeouts
1668 * (observed in real case).
1669 */
1670#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1671 start_from = list->prev; /* assume we'll queue to the end of the list */
1672 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1673 start_from = start_from->prev;
1674#if STATTIME > 0
1675 stats_tsk_lsrch++;
1676#endif
1677 }
1678#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001679 /* insert the unlinked <task> into the list, searching after position <start_from> */
1680 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1681 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001682#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001683 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001684#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001685 }
willy tarreau750a4722005-12-17 13:21:24 +01001686#endif /* WE_REALLY_... */
1687
willy tarreau0f7af912005-12-17 12:21:26 +01001688 /* we need to unlink it now */
1689 task_delete(task);
1690 }
1691 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001692#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001693 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001694#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001695#ifdef LEFT_TO_TOP /* not very good */
1696 start_from = list;
1697 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1698 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001699#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001700 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001701#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001702 }
1703#else
1704 start_from = task->prev->prev; /* valid because of the previous test above */
1705 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1706 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001707#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001708 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001709#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001710 }
1711#endif
1712 /* we need to unlink it now */
1713 task_delete(task);
1714 }
1715 task->prev = start_from;
1716 task->next = start_from->next;
1717 task->next->prev = task;
1718 start_from->next = task;
1719 return task;
1720}
1721
1722
1723/*********************************************************************/
1724/* more specific functions ***************************************/
1725/*********************************************************************/
1726
1727/* some prototypes */
1728static int maintain_proxies(void);
1729
willy tarreaub952e1d2005-12-18 01:31:20 +01001730/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001731 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1732 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001733static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001734#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001735 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1736#else
willy tarreaua1598082005-12-17 13:08:06 +01001737#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001738 return getsockname(fd, (struct sockaddr *)sa, salen);
1739#else
1740 return -1;
1741#endif
1742#endif
1743}
1744
1745/*
1746 * frees the context associated to a session. It must have been removed first.
1747 */
1748static inline void session_free(struct session *s) {
1749 if (s->req)
1750 pool_free(buffer, s->req);
1751 if (s->rep)
1752 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001753
1754 if (s->rsp_cap != NULL) {
1755 struct cap_hdr *h;
1756 for (h = s->proxy->rsp_cap; h; h = h->next) {
1757 if (s->rsp_cap[h->index] != NULL)
1758 pool_free_to(h->pool, s->rsp_cap[h->index]);
1759 }
1760 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1761 }
1762 if (s->req_cap != NULL) {
1763 struct cap_hdr *h;
1764 for (h = s->proxy->req_cap; h; h = h->next) {
1765 if (s->req_cap[h->index] != NULL)
1766 pool_free_to(h->pool, s->req_cap[h->index]);
1767 }
1768 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1769 }
1770
willy tarreaua1598082005-12-17 13:08:06 +01001771 if (s->logs.uri)
1772 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001773 if (s->logs.cli_cookie)
1774 pool_free(capture, s->logs.cli_cookie);
1775 if (s->logs.srv_cookie)
1776 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001777
willy tarreau5cbea6f2005-12-17 12:48:26 +01001778 pool_free(session, s);
1779}
1780
willy tarreau0f7af912005-12-17 12:21:26 +01001781
1782/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001783 * This function tries to find a running server for the proxy <px>. A first
1784 * pass looks for active servers, and if none is found, a second pass also
1785 * looks for backup servers.
1786 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1787 */
1788static inline struct server *find_server(struct proxy *px) {
1789 struct server *srv = px->cursrv;
1790 int ignore_backup = 1;
1791
1792 do {
1793 do {
1794 if (srv == NULL)
1795 srv = px->srv;
1796 if (srv->state & SRV_RUNNING
1797 && !((srv->state & SRV_BACKUP) && ignore_backup))
1798 return srv;
1799 srv = srv->next;
1800 } while (srv != px->cursrv);
Willy TARREAU3481c462006-03-01 22:37:57 +01001801
1802 /* By default, we look for the first backup server if all others are
1803 * DOWN. But in some cases, it may be desirable to load-balance across
1804 * all backup servers.
1805 */
1806 if (!(px->options & PR_O_USE_ALL_BK))
1807 srv = px->srv;
1808
willy tarreau8337c6b2005-12-17 13:41:01 +01001809 } while (ignore_backup--);
1810 return NULL;
1811}
1812
1813/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001814 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01001815 * is set, or to the dispatch server if (s->direct) is 0.
1816 * It can return one of :
1817 * - SN_ERR_NONE if everything's OK
1818 * - SN_ERR_SRVTO if there are no more servers
1819 * - SN_ERR_SRVCL if the connection was refused by the server
1820 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1821 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1822 * - SN_ERR_INTERNAL for any other purely internal errors
1823 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01001824 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001825int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001826 int fd;
1827
willy tarreau12350152005-12-18 01:03:27 +01001828#ifdef DEBUG_FULL
1829 fprintf(stderr,"connect_server : s=%p\n",s);
1830#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001831
willy tarreaue39cd132005-12-17 13:00:18 +01001832 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001833 s->srv_addr = s->srv->addr;
1834 }
1835 else if (s->proxy->options & PR_O_BALANCE) {
1836 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001837 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001838
willy tarreau8337c6b2005-12-17 13:41:01 +01001839 srv = find_server(s->proxy);
1840
1841 if (srv == NULL) /* no server left */
willy tarreaub1285d52005-12-18 01:20:14 +01001842 return SN_ERR_SRVTO;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001843
willy tarreau8337c6b2005-12-17 13:41:01 +01001844 s->srv_addr = srv->addr;
1845 s->srv = srv;
1846 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001847 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001848 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01001849 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001850 }
willy tarreaua1598082005-12-17 13:08:06 +01001851 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001852 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001853 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001854 }
1855 else if (s->proxy->options & PR_O_TRANSP) {
1856 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01001857 socklen_t salen = sizeof(s->srv_addr);
1858
willy tarreau5cbea6f2005-12-17 12:48:26 +01001859 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1860 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001861 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001862 }
1863 }
willy tarreau0f7af912005-12-17 12:21:26 +01001864
willy tarreaua41a8b42005-12-17 14:02:24 +01001865 /* if this server remaps proxied ports, we'll use
1866 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001867 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001868 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01001869 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01001870
willy tarreaub952e1d2005-12-18 01:31:20 +01001871 if (!(s->proxy->options & PR_O_TRANSP) ||
1872 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01001873 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1874 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1875 }
1876
willy tarreau0f7af912005-12-17 12:21:26 +01001877 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001878 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001879
1880 if (errno == ENFILE)
1881 send_log(s->proxy, LOG_EMERG,
1882 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
1883 s->proxy->id, maxfd);
1884 else if (errno == EMFILE)
1885 send_log(s->proxy, LOG_EMERG,
1886 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
1887 s->proxy->id, maxfd);
1888 else if (errno == ENOBUFS || errno == ENOMEM)
1889 send_log(s->proxy, LOG_EMERG,
1890 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
1891 s->proxy->id, maxfd);
1892 /* this is a resource error */
1893 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01001894 }
1895
willy tarreau9fe663a2005-12-17 13:02:59 +01001896 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01001897 /* do not log anything there, it's a normal condition when this option
1898 * is used to serialize connections to a server !
1899 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001900 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1901 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001902 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001903 }
1904
willy tarreau0f7af912005-12-17 12:21:26 +01001905 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1906 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001907 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001908 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001909 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001910 }
1911
willy tarreaub952e1d2005-12-18 01:31:20 +01001912 if (s->proxy->options & PR_O_TCP_SRV_KA)
1913 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
1914
willy tarreau0174f312005-12-18 01:02:42 +01001915 /* allow specific binding :
1916 * - server-specific at first
1917 * - proxy-specific next
1918 */
1919 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
1920 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1921 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
1922 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
1923 s->proxy->id, s->srv->id);
1924 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001925 send_log(s->proxy, LOG_EMERG,
1926 "Cannot bind to source address before connect() for server %s/%s.\n",
1927 s->proxy->id, s->srv->id);
1928 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001929 }
1930 }
1931 else if (s->proxy->options & PR_O_BIND_SRC) {
1932 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1933 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1934 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1935 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001936 send_log(s->proxy, LOG_EMERG,
1937 "Cannot bind to source address before connect() for server %s/%s.\n",
1938 s->proxy->id, s->srv->id);
1939 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001940 }
willy tarreaua1598082005-12-17 13:08:06 +01001941 }
1942
willy tarreaub1285d52005-12-18 01:20:14 +01001943 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
1944 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
1945
1946 if (errno == EAGAIN || errno == EADDRINUSE) {
1947 char *msg;
1948 if (errno == EAGAIN) /* no free ports left, try again later */
1949 msg = "no free ports";
1950 else
1951 msg = "local address already in use";
1952
1953 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01001954 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001955 send_log(s->proxy, LOG_EMERG,
1956 "Connect() failed for server %s/%s: %s.\n",
1957 s->proxy->id, s->srv->id, msg);
1958 return SN_ERR_RESOURCE;
1959 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001960 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01001961 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001962 return SN_ERR_SRVTO;
1963 } else {
1964 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01001965 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01001966 close(fd);
1967 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01001968 }
1969 }
1970
willy tarreau5cbea6f2005-12-17 12:48:26 +01001971 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001972 fdtab[fd].read = &event_srv_read;
1973 fdtab[fd].write = &event_srv_write;
1974 fdtab[fd].state = FD_STCONN; /* connection in progress */
1975
1976 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01001977#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
1978 if (PrevReadEvent) {
1979 assert(!(FD_ISSET(fd, PrevReadEvent)));
1980 assert(!(FD_ISSET(fd, PrevWriteEvent)));
1981 }
1982#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001983
1984 fd_insert(fd);
1985
1986 if (s->proxy->contimeout)
1987 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1988 else
1989 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01001990 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01001991}
1992
1993/*
1994 * this function is called on a read event from a client socket.
1995 * It returns 0.
1996 */
1997int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001998 struct task *t = fdtab[fd].owner;
1999 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002000 struct buffer *b = s->req;
2001 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002002
willy tarreau12350152005-12-18 01:03:27 +01002003#ifdef DEBUG_FULL
2004 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2005#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002006
willy tarreau0f7af912005-12-17 12:21:26 +01002007 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002008#ifdef FILL_BUFFERS
2009 while (1)
2010#else
2011 do
2012#endif
2013 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002014 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2015 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002016 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002017 }
2018 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002019 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002020 }
2021 else {
2022 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002023 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2024 * since it means that the rewrite protection has been removed. This
2025 * implies that the if statement can be removed.
2026 */
2027 if (max > b->rlim - b->data)
2028 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002029 }
2030
2031 if (max == 0) { /* not anymore room to store data */
2032 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002033 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002034 }
2035
willy tarreau3242e862005-12-17 12:27:53 +01002036#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002037 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002038 int skerr;
2039 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002040
willy tarreau5cbea6f2005-12-17 12:48:26 +01002041 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2042 if (skerr)
2043 ret = -1;
2044 else
2045 ret = recv(fd, b->r, max, 0);
2046 }
willy tarreau3242e862005-12-17 12:27:53 +01002047#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002048 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002049#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002050 if (ret > 0) {
2051 b->r += ret;
2052 b->l += ret;
2053 s->res_cr = RES_DATA;
2054
2055 if (b->r == b->data + BUFSIZE) {
2056 b->r = b->data; /* wrap around the buffer */
2057 }
willy tarreaua1598082005-12-17 13:08:06 +01002058
2059 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002060 /* we hope to read more data or to get a close on next round */
2061 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002062 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002063 else if (ret == 0) {
2064 s->res_cr = RES_NULL;
2065 break;
2066 }
2067 else if (errno == EAGAIN) {/* ignore EAGAIN */
2068 break;
2069 }
2070 else {
2071 s->res_cr = RES_ERROR;
2072 fdtab[fd].state = FD_STERROR;
2073 break;
2074 }
2075 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002076#ifndef FILL_BUFFERS
2077 while (0);
2078#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002079 }
2080 else {
2081 s->res_cr = RES_ERROR;
2082 fdtab[fd].state = FD_STERROR;
2083 }
2084
willy tarreau5cbea6f2005-12-17 12:48:26 +01002085 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002086 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002087 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2088 else
2089 tv_eternity(&s->crexpire);
2090
2091 task_wakeup(&rq, t);
2092 }
willy tarreau0f7af912005-12-17 12:21:26 +01002093
willy tarreau0f7af912005-12-17 12:21:26 +01002094 return 0;
2095}
2096
2097
2098/*
2099 * this function is called on a read event from a server socket.
2100 * It returns 0.
2101 */
2102int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002103 struct task *t = fdtab[fd].owner;
2104 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002105 struct buffer *b = s->rep;
2106 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002107
willy tarreau12350152005-12-18 01:03:27 +01002108#ifdef DEBUG_FULL
2109 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2110#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002111
willy tarreau0f7af912005-12-17 12:21:26 +01002112 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002113#ifdef FILL_BUFFERS
2114 while (1)
2115#else
2116 do
2117#endif
2118 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002119 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2120 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002121 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002122 }
2123 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002124 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002125 }
2126 else {
2127 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002128 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2129 * since it means that the rewrite protection has been removed. This
2130 * implies that the if statement can be removed.
2131 */
2132 if (max > b->rlim - b->data)
2133 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002134 }
2135
2136 if (max == 0) { /* not anymore room to store data */
2137 FD_CLR(fd, StaticReadEvent);
2138 break;
2139 }
2140
willy tarreau3242e862005-12-17 12:27:53 +01002141#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002142 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002143 int skerr;
2144 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002145
willy tarreau5cbea6f2005-12-17 12:48:26 +01002146 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2147 if (skerr)
2148 ret = -1;
2149 else
2150 ret = recv(fd, b->r, max, 0);
2151 }
willy tarreau3242e862005-12-17 12:27:53 +01002152#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002153 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002154#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002155 if (ret > 0) {
2156 b->r += ret;
2157 b->l += ret;
2158 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002159
willy tarreau5cbea6f2005-12-17 12:48:26 +01002160 if (b->r == b->data + BUFSIZE) {
2161 b->r = b->data; /* wrap around the buffer */
2162 }
willy tarreaua1598082005-12-17 13:08:06 +01002163
2164 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002165 /* we hope to read more data or to get a close on next round */
2166 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002167 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002168 else if (ret == 0) {
2169 s->res_sr = RES_NULL;
2170 break;
2171 }
2172 else if (errno == EAGAIN) {/* ignore EAGAIN */
2173 break;
2174 }
2175 else {
2176 s->res_sr = RES_ERROR;
2177 fdtab[fd].state = FD_STERROR;
2178 break;
2179 }
2180 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002181#ifndef FILL_BUFFERS
2182 while (0);
2183#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002184 }
2185 else {
2186 s->res_sr = RES_ERROR;
2187 fdtab[fd].state = FD_STERROR;
2188 }
2189
willy tarreau5cbea6f2005-12-17 12:48:26 +01002190 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002191 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002192 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2193 else
2194 tv_eternity(&s->srexpire);
2195
2196 task_wakeup(&rq, t);
2197 }
willy tarreau0f7af912005-12-17 12:21:26 +01002198
willy tarreau0f7af912005-12-17 12:21:26 +01002199 return 0;
2200}
2201
2202/*
2203 * this function is called on a write event from a client socket.
2204 * It returns 0.
2205 */
2206int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002207 struct task *t = fdtab[fd].owner;
2208 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002209 struct buffer *b = s->rep;
2210 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002211
willy tarreau12350152005-12-18 01:03:27 +01002212#ifdef DEBUG_FULL
2213 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2214#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002215
2216 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002217 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002218 // max = BUFSIZE; BUG !!!!
2219 max = 0;
2220 }
2221 else if (b->r > b->w) {
2222 max = b->r - b->w;
2223 }
2224 else
2225 max = b->data + BUFSIZE - b->w;
2226
willy tarreau0f7af912005-12-17 12:21:26 +01002227 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002228 if (max == 0) {
2229 s->res_cw = RES_NULL;
2230 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002231 tv_eternity(&s->cwexpire);
2232 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002233 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002234 }
2235
willy tarreau3242e862005-12-17 12:27:53 +01002236#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002237 {
2238 int skerr;
2239 socklen_t lskerr = sizeof(skerr);
2240
2241 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2242 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002243 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002244 else
willy tarreau3242e862005-12-17 12:27:53 +01002245 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002246 }
willy tarreau3242e862005-12-17 12:27:53 +01002247#else
willy tarreau0f7af912005-12-17 12:21:26 +01002248 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002249#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002250
2251 if (ret > 0) {
2252 b->l -= ret;
2253 b->w += ret;
2254
2255 s->res_cw = RES_DATA;
2256
2257 if (b->w == b->data + BUFSIZE) {
2258 b->w = b->data; /* wrap around the buffer */
2259 }
2260 }
2261 else if (ret == 0) {
2262 /* nothing written, just make as if we were never called */
2263// s->res_cw = RES_NULL;
2264 return 0;
2265 }
2266 else if (errno == EAGAIN) /* ignore EAGAIN */
2267 return 0;
2268 else {
2269 s->res_cw = RES_ERROR;
2270 fdtab[fd].state = FD_STERROR;
2271 }
2272 }
2273 else {
2274 s->res_cw = RES_ERROR;
2275 fdtab[fd].state = FD_STERROR;
2276 }
2277
willy tarreaub1ff9db2005-12-17 13:51:03 +01002278 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002279 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002280 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2281 s->crexpire = s->cwexpire;
2282 }
willy tarreau0f7af912005-12-17 12:21:26 +01002283 else
2284 tv_eternity(&s->cwexpire);
2285
willy tarreau5cbea6f2005-12-17 12:48:26 +01002286 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002287 return 0;
2288}
2289
2290
2291/*
2292 * this function is called on a write event from a server socket.
2293 * It returns 0.
2294 */
2295int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002296 struct task *t = fdtab[fd].owner;
2297 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002298 struct buffer *b = s->req;
2299 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002300
willy tarreau12350152005-12-18 01:03:27 +01002301#ifdef DEBUG_FULL
2302 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2303#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002304
2305 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002306 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002307 // max = BUFSIZE; BUG !!!!
2308 max = 0;
2309 }
2310 else if (b->r > b->w) {
2311 max = b->r - b->w;
2312 }
2313 else
2314 max = b->data + BUFSIZE - b->w;
2315
willy tarreau0f7af912005-12-17 12:21:26 +01002316 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002317 if (max == 0) {
2318 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002319 if (s->srv_state == SV_STCONN) {
2320 int skerr;
2321 socklen_t lskerr = sizeof(skerr);
2322 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2323 if (skerr) {
2324 s->res_sw = RES_ERROR;
2325 fdtab[fd].state = FD_STERROR;
2326 task_wakeup(&rq, t);
2327 tv_eternity(&s->swexpire);
2328 FD_CLR(fd, StaticWriteEvent);
2329 return 0;
2330 }
2331 }
2332
willy tarreau0f7af912005-12-17 12:21:26 +01002333 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002334 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002335 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002336 tv_eternity(&s->swexpire);
2337 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002338 return 0;
2339 }
2340
willy tarreau3242e862005-12-17 12:27:53 +01002341#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002342 {
2343 int skerr;
2344 socklen_t lskerr = sizeof(skerr);
2345 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2346 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002347 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002348 else
willy tarreau3242e862005-12-17 12:27:53 +01002349 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002350 }
willy tarreau3242e862005-12-17 12:27:53 +01002351#else
willy tarreau0f7af912005-12-17 12:21:26 +01002352 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002353#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002354 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002355 if (ret > 0) {
2356 b->l -= ret;
2357 b->w += ret;
2358
2359 s->res_sw = RES_DATA;
2360
2361 if (b->w == b->data + BUFSIZE) {
2362 b->w = b->data; /* wrap around the buffer */
2363 }
2364 }
2365 else if (ret == 0) {
2366 /* nothing written, just make as if we were never called */
2367 // s->res_sw = RES_NULL;
2368 return 0;
2369 }
2370 else if (errno == EAGAIN) /* ignore EAGAIN */
2371 return 0;
2372 else {
2373 s->res_sw = RES_ERROR;
2374 fdtab[fd].state = FD_STERROR;
2375 }
2376 }
2377 else {
2378 s->res_sw = RES_ERROR;
2379 fdtab[fd].state = FD_STERROR;
2380 }
2381
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002382 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2383 * otherwise it could loop indefinitely !
2384 */
2385 if (s->srv_state != SV_STCONN) {
2386 if (s->proxy->srvtimeout) {
2387 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
2388 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2389 s->srexpire = s->swexpire;
2390 }
2391 else
2392 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002393 }
willy tarreau0f7af912005-12-17 12:21:26 +01002394
willy tarreau5cbea6f2005-12-17 12:48:26 +01002395 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002396 return 0;
2397}
2398
2399
2400/*
willy tarreaue39cd132005-12-17 13:00:18 +01002401 * returns a message to the client ; the connection is shut down for read,
2402 * and the request is cleared so that no server connection can be initiated.
2403 * The client must be in a valid state for this (HEADER, DATA ...).
2404 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002405 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002406 */
2407void client_retnclose(struct session *s, int len, const char *msg) {
2408 FD_CLR(s->cli_fd, StaticReadEvent);
2409 FD_SET(s->cli_fd, StaticWriteEvent);
2410 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002411 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002412 shutdown(s->cli_fd, SHUT_RD);
2413 s->cli_state = CL_STSHUTR;
2414 strcpy(s->rep->data, msg);
2415 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002416 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002417 s->rep->r += len;
2418 s->req->l = 0;
2419}
2420
2421
2422/*
2423 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002424 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002425 */
2426void client_return(struct session *s, int len, const char *msg) {
2427 strcpy(s->rep->data, msg);
2428 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002429 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002430 s->rep->r += len;
2431 s->req->l = 0;
2432}
2433
willy tarreau9fe663a2005-12-17 13:02:59 +01002434/*
2435 * send a log for the session when we have enough info about it
2436 */
2437void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002438 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002439 struct proxy *p = s->proxy;
2440 int log;
2441 char *uri;
2442 char *pxid;
2443 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002444 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002445
2446 /* This is a first attempt at a better logging system.
2447 * For now, we rely on send_log() to provide the date, although it obviously
2448 * is the date of the log and not of the request, and most fields are not
2449 * computed.
2450 */
2451
willy tarreaua1598082005-12-17 13:08:06 +01002452 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002453
willy tarreau8a86dbf2005-12-18 00:45:59 +01002454 if (s->cli_addr.ss_family == AF_INET)
2455 inet_ntop(AF_INET,
2456 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2457 pn, sizeof(pn));
2458 else
2459 inet_ntop(AF_INET6,
2460 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2461 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002462
willy tarreauc1cae632005-12-17 14:12:23 +01002463 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002464 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002465 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002466
willy tarreauc1cae632005-12-17 14:12:23 +01002467 tm = localtime(&s->logs.tv_accept.tv_sec);
2468 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002469 char tmpline[MAX_SYSLOG_LEN], *h;
2470 int hdr;
2471
2472 h = tmpline;
2473 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2474 *(h++) = ' ';
2475 *(h++) = '{';
2476 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2477 if (hdr)
2478 *(h++) = '|';
2479 if (s->req_cap[hdr] != NULL)
2480 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2481 }
2482 *(h++) = '}';
2483 }
2484
2485 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2486 *(h++) = ' ';
2487 *(h++) = '{';
2488 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2489 if (hdr)
2490 *(h++) = '|';
2491 if (s->rsp_cap[hdr] != NULL)
2492 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2493 }
2494 *(h++) = '}';
2495 }
2496
2497 if (h < tmpline + sizeof(tmpline) - 4) {
2498 *(h++) = ' ';
2499 *(h++) = '"';
2500 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2501 *(h++) = '"';
2502 }
2503 *h = '\0';
2504
willy tarreau0fe39652005-12-18 01:25:24 +01002505 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%s%d %d %s%lld %s %s %c%c%c%c %d/%d%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002506 pn,
2507 (s->cli_addr.ss_family == AF_INET) ?
2508 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2509 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002510 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2511 tm->tm_hour, tm->tm_min, tm->tm_sec,
2512 pxid, srv,
2513 s->logs.t_request,
2514 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2515 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002516 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2517 s->logs.status,
2518 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002519 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2520 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002521 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2522 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2523 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2524 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau0fe39652005-12-18 01:25:24 +01002525 p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002526 }
2527 else {
willy tarreau0fe39652005-12-18 01:25:24 +01002528 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c %d/%d\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002529 pn,
2530 (s->cli_addr.ss_family == AF_INET) ?
2531 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2532 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002533 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2534 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002535 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002536 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002537 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2538 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002539 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002540 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2541 p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002542 }
2543
2544 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002545}
2546
willy tarreaue39cd132005-12-17 13:00:18 +01002547
2548/*
willy tarreau0f7af912005-12-17 12:21:26 +01002549 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002550 * to an accept. It tries to accept as many connections as possible.
2551 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002552 */
2553int event_accept(int fd) {
2554 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002555 struct session *s;
2556 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002557 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01002558 int max_accept;
2559
2560 if (global.nbproc > 1)
2561 max_accept = 8; /* let other processes catch some connections too */
2562 else
2563 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01002564
willy tarreauc2becdc2006-03-19 19:36:48 +01002565 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002566 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002567 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002568
willy tarreaub1285d52005-12-18 01:20:14 +01002569 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2570 switch (errno) {
2571 case EAGAIN:
2572 case EINTR:
2573 case ECONNABORTED:
2574 return 0; /* nothing more to accept */
2575 case ENFILE:
2576 send_log(p, LOG_EMERG,
2577 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2578 p->id, maxfd);
2579 return 0;
2580 case EMFILE:
2581 send_log(p, LOG_EMERG,
2582 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2583 p->id, maxfd);
2584 return 0;
2585 case ENOBUFS:
2586 case ENOMEM:
2587 send_log(p, LOG_EMERG,
2588 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2589 p->id, maxfd);
2590 return 0;
2591 default:
2592 return 0;
2593 }
2594 }
willy tarreau0f7af912005-12-17 12:21:26 +01002595
willy tarreau5cbea6f2005-12-17 12:48:26 +01002596 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2597 Alert("out of memory in event_accept().\n");
2598 FD_CLR(fd, StaticReadEvent);
2599 p->state = PR_STIDLE;
2600 close(cfd);
2601 return 0;
2602 }
willy tarreau0f7af912005-12-17 12:21:26 +01002603
willy tarreaub1285d52005-12-18 01:20:14 +01002604 /* if this session comes from a known monitoring system, we want to ignore
2605 * it as soon as possible, which means closing it immediately for TCP.
2606 */
2607 s->flags = 0;
2608 if (addr.ss_family == AF_INET &&
2609 p->mon_mask.s_addr &&
2610 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2611 if (p->mode == PR_MODE_TCP) {
2612 close(cfd);
2613 pool_free(session, s);
2614 continue;
2615 }
2616 s->flags |= SN_MONITOR;
2617 }
2618
willy tarreau5cbea6f2005-12-17 12:48:26 +01002619 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2620 Alert("out of memory in event_accept().\n");
2621 FD_CLR(fd, StaticReadEvent);
2622 p->state = PR_STIDLE;
2623 close(cfd);
2624 pool_free(session, s);
2625 return 0;
2626 }
willy tarreau0f7af912005-12-17 12:21:26 +01002627
willy tarreau5cbea6f2005-12-17 12:48:26 +01002628 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002629 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002630 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2631 close(cfd);
2632 pool_free(task, t);
2633 pool_free(session, s);
2634 return 0;
2635 }
willy tarreau0f7af912005-12-17 12:21:26 +01002636
willy tarreau5cbea6f2005-12-17 12:48:26 +01002637 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2638 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2639 (char *) &one, sizeof(one)) == -1)) {
2640 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2641 close(cfd);
2642 pool_free(task, t);
2643 pool_free(session, s);
2644 return 0;
2645 }
willy tarreau0f7af912005-12-17 12:21:26 +01002646
willy tarreaub952e1d2005-12-18 01:31:20 +01002647 if (p->options & PR_O_TCP_CLI_KA)
2648 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2649
willy tarreau9fe663a2005-12-17 13:02:59 +01002650 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2651 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2652 t->state = TASK_IDLE;
2653 t->process = process_session;
2654 t->context = s;
2655
2656 s->task = t;
2657 s->proxy = p;
2658 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2659 s->srv_state = SV_STIDLE;
2660 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002661
willy tarreau9fe663a2005-12-17 13:02:59 +01002662 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2663 s->cli_fd = cfd;
2664 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002665 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002666 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002667
willy tarreaub1285d52005-12-18 01:20:14 +01002668 if (s->flags & SN_MONITOR)
2669 s->logs.logwait = 0;
2670 else
2671 s->logs.logwait = p->to_log;
2672
willy tarreaua1598082005-12-17 13:08:06 +01002673 s->logs.tv_accept = now;
2674 s->logs.t_request = -1;
2675 s->logs.t_connect = -1;
2676 s->logs.t_data = -1;
2677 s->logs.t_close = 0;
2678 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002679 s->logs.cli_cookie = NULL;
2680 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002681 s->logs.status = -1;
2682 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002683
willy tarreau2f6ba652005-12-17 13:57:42 +01002684 s->uniq_id = totalconn;
2685
willy tarreau4302f492005-12-18 01:00:37 +01002686 if (p->nb_req_cap > 0) {
2687 if ((s->req_cap =
2688 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2689 == NULL) { /* no memory */
2690 close(cfd); /* nothing can be done for this fd without memory */
2691 pool_free(task, t);
2692 pool_free(session, s);
2693 return 0;
2694 }
2695 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2696 }
2697 else
2698 s->req_cap = NULL;
2699
2700 if (p->nb_rsp_cap > 0) {
2701 if ((s->rsp_cap =
2702 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2703 == NULL) { /* no memory */
2704 if (s->req_cap != NULL)
2705 pool_free_to(p->req_cap_pool, s->req_cap);
2706 close(cfd); /* nothing can be done for this fd without memory */
2707 pool_free(task, t);
2708 pool_free(session, s);
2709 return 0;
2710 }
2711 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2712 }
2713 else
2714 s->rsp_cap = NULL;
2715
willy tarreau5cbea6f2005-12-17 12:48:26 +01002716 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2717 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002718 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002719 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002720
willy tarreau8a86dbf2005-12-18 00:45:59 +01002721 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002722 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002723 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002724 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002725
willy tarreau9fe663a2005-12-17 13:02:59 +01002726 if (p->to_log) {
2727 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002728 if (s->logs.logwait & LW_CLIP)
2729 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002730 sess_log(s);
2731 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002732 else if (s->cli_addr.ss_family == AF_INET) {
2733 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2734 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2735 sn, sizeof(sn)) &&
2736 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2737 pn, sizeof(pn))) {
2738 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2739 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2740 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2741 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2742 }
2743 }
2744 else {
2745 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2746 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2747 sn, sizeof(sn)) &&
2748 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2749 pn, sizeof(pn))) {
2750 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2751 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2752 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2753 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2754 }
2755 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002756 }
willy tarreau0f7af912005-12-17 12:21:26 +01002757
willy tarreau982249e2005-12-18 00:57:06 +01002758 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002759 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002760 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002761 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002762 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002763 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002764 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002765 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002766
willy tarreau8a86dbf2005-12-18 00:45:59 +01002767 if (s->cli_addr.ss_family == AF_INET) {
2768 char pn[INET_ADDRSTRLEN];
2769 inet_ntop(AF_INET,
2770 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2771 pn, sizeof(pn));
2772
2773 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2774 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2775 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2776 }
2777 else {
2778 char pn[INET6_ADDRSTRLEN];
2779 inet_ntop(AF_INET6,
2780 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2781 pn, sizeof(pn));
2782
2783 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2784 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2785 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2786 }
2787
willy tarreauef900ab2005-12-17 12:52:52 +01002788 write(1, trash, len);
2789 }
willy tarreau0f7af912005-12-17 12:21:26 +01002790
willy tarreau5cbea6f2005-12-17 12:48:26 +01002791 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002792 if (s->rsp_cap != NULL)
2793 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2794 if (s->req_cap != NULL)
2795 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002796 close(cfd); /* nothing can be done for this fd without memory */
2797 pool_free(task, t);
2798 pool_free(session, s);
2799 return 0;
2800 }
willy tarreau4302f492005-12-18 01:00:37 +01002801
willy tarreau5cbea6f2005-12-17 12:48:26 +01002802 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002803 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002804 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2805 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002806 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002807 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002808
willy tarreau5cbea6f2005-12-17 12:48:26 +01002809 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2810 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002811 if (s->rsp_cap != NULL)
2812 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2813 if (s->req_cap != NULL)
2814 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002815 close(cfd); /* nothing can be done for this fd without memory */
2816 pool_free(task, t);
2817 pool_free(session, s);
2818 return 0;
2819 }
2820 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002821 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002822 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 +01002823
willy tarreau5cbea6f2005-12-17 12:48:26 +01002824 fdtab[cfd].read = &event_cli_read;
2825 fdtab[cfd].write = &event_cli_write;
2826 fdtab[cfd].owner = t;
2827 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002828
willy tarreaub1285d52005-12-18 01:20:14 +01002829 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2830 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2831 /* Either we got a request from a monitoring system on an HTTP instance,
2832 * or we're in health check mode with the 'httpchk' option enabled. In
2833 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2834 */
2835 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2836 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2837 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002838 }
2839 else {
2840 FD_SET(cfd, StaticReadEvent);
2841 }
2842
willy tarreaub952e1d2005-12-18 01:31:20 +01002843#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2844 if (PrevReadEvent) {
2845 assert(!(FD_ISSET(cfd, PrevReadEvent)));
2846 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
2847 }
2848#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002849 fd_insert(cfd);
2850
2851 tv_eternity(&s->cnexpire);
2852 tv_eternity(&s->srexpire);
2853 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01002854 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002855 tv_eternity(&s->cwexpire);
2856
willy tarreaub1285d52005-12-18 01:20:14 +01002857 if (s->proxy->clitimeout) {
2858 if (FD_ISSET(cfd, StaticReadEvent))
2859 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2860 if (FD_ISSET(cfd, StaticWriteEvent))
2861 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
2862 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002863
willy tarreaub1285d52005-12-18 01:20:14 +01002864 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002865
2866 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002867
2868 if (p->mode != PR_MODE_HEALTH)
2869 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002870
2871 p->nbconn++;
2872 actconn++;
2873 totalconn++;
2874
willy tarreaub952e1d2005-12-18 01:31:20 +01002875 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002876 } /* end of while (p->nbconn < p->maxconn) */
2877 return 0;
2878}
willy tarreau0f7af912005-12-17 12:21:26 +01002879
willy tarreau0f7af912005-12-17 12:21:26 +01002880
willy tarreau5cbea6f2005-12-17 12:48:26 +01002881/*
2882 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002883 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2884 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002885 * or -1 if an error occured.
2886 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002887int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002888 struct task *t = fdtab[fd].owner;
2889 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002890 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01002891 socklen_t lskerr = sizeof(skerr);
2892
willy tarreau05be12b2006-03-19 19:35:00 +01002893 skerr = 1;
2894 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
2895 || (skerr != 0)) {
2896 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002897 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01002898 fdtab[fd].state = FD_STERROR;
2899 FD_CLR(fd, StaticWriteEvent);
2900 }
willy tarreaua4a583a2005-12-18 01:39:19 +01002901 else if (s->result != -1) {
2902 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002903 if (s->proxy->options & PR_O_HTTP_CHK) {
2904 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002905 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002906 * so we'll send the request, and won't wake the checker up now.
2907 */
2908#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002909 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002910#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002911 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002912#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002913 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002914 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2915 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2916 return 0;
2917 }
willy tarreau05be12b2006-03-19 19:35:00 +01002918 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002919 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01002920 FD_CLR(fd, StaticWriteEvent);
2921 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002922 }
2923 else {
2924 /* good TCP connection is enough */
2925 s->result = 1;
2926 }
2927 }
2928
2929 task_wakeup(&rq, t);
2930 return 0;
2931}
2932
willy tarreau0f7af912005-12-17 12:21:26 +01002933
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002934/*
2935 * This function is used only for server health-checks. It handles
2936 * the server's reply to an HTTP request. It returns 1 if the server replies
2937 * 2xx or 3xx (valid responses), or -1 in other cases.
2938 */
2939int event_srv_chk_r(int fd) {
2940 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01002941 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002942 struct task *t = fdtab[fd].owner;
2943 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01002944 int skerr;
2945 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002946
willy tarreaua4a583a2005-12-18 01:39:19 +01002947 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002948
willy tarreau05be12b2006-03-19 19:35:00 +01002949 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2950 if (!skerr) {
2951#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002952 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002953#else
willy tarreau05be12b2006-03-19 19:35:00 +01002954 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2955 * but the connection was closed on the remote end. Fortunately, recv still
2956 * works correctly and we don't need to do the getsockopt() on linux.
2957 */
2958 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002959#endif
willy tarreau05be12b2006-03-19 19:35:00 +01002960
2961 if ((len >= sizeof("HTTP/1.0 000")) &&
2962 !memcmp(reply, "HTTP/1.", 7) &&
2963 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2964 result = 1;
2965 }
2966
2967 if (result == -1)
2968 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01002969
2970 if (s->result != -1)
2971 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002972
2973 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002974 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002975 return 0;
2976}
2977
2978
2979/*
2980 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2981 * and moves <end> just after the end of <str>.
2982 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2983 * the shift value (positive or negative) is returned.
2984 * If there's no space left, the move is not done.
2985 *
2986 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002987int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002988 int delta;
2989 int len;
2990
2991 len = strlen(str);
2992 delta = len - (end - pos);
2993
2994 if (delta + b->r >= b->data + BUFSIZE)
2995 return 0; /* no space left */
2996
2997 /* first, protect the end of the buffer */
2998 memmove(end + delta, end, b->data + b->l - end);
2999
3000 /* now, copy str over pos */
3001 memcpy(pos, str,len);
3002
willy tarreau5cbea6f2005-12-17 12:48:26 +01003003 /* we only move data after the displaced zone */
3004 if (b->r > pos) b->r += delta;
3005 if (b->w > pos) b->w += delta;
3006 if (b->h > pos) b->h += delta;
3007 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003008 b->l += delta;
3009
3010 return delta;
3011}
3012
willy tarreau8337c6b2005-12-17 13:41:01 +01003013/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003014 * len is 0.
3015 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003016int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003017 int delta;
3018
3019 delta = len - (end - pos);
3020
3021 if (delta + b->r >= b->data + BUFSIZE)
3022 return 0; /* no space left */
3023
Willy TARREAUe78ae262006-01-08 01:24:12 +01003024 if (b->data + b->l < end)
3025 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3026 return 0;
3027
willy tarreau0f7af912005-12-17 12:21:26 +01003028 /* first, protect the end of the buffer */
3029 memmove(end + delta, end, b->data + b->l - end);
3030
3031 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003032 if (len)
3033 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003034
willy tarreau5cbea6f2005-12-17 12:48:26 +01003035 /* we only move data after the displaced zone */
3036 if (b->r > pos) b->r += delta;
3037 if (b->w > pos) b->w += delta;
3038 if (b->h > pos) b->h += delta;
3039 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003040 b->l += delta;
3041
3042 return delta;
3043}
3044
3045
3046int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3047 char *old_dst = dst;
3048
3049 while (*str) {
3050 if (*str == '\\') {
3051 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003052 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003053 int len, num;
3054
3055 num = *str - '0';
3056 str++;
3057
willy tarreau8a86dbf2005-12-18 00:45:59 +01003058 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003059 len = matches[num].rm_eo - matches[num].rm_so;
3060 memcpy(dst, src + matches[num].rm_so, len);
3061 dst += len;
3062 }
3063
3064 }
3065 else if (*str == 'x') {
3066 unsigned char hex1, hex2;
3067 str++;
3068
willy tarreauc1f47532005-12-18 01:08:26 +01003069 hex1 = toupper(*str++) - '0';
3070 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003071
3072 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3073 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3074 *dst++ = (hex1<<4) + hex2;
3075 }
3076 else
3077 *dst++ = *str++;
3078 }
3079 else
3080 *dst++ = *str++;
3081 }
3082 *dst = 0;
3083 return dst - old_dst;
3084}
3085
willy tarreauc1f47532005-12-18 01:08:26 +01003086static int ishex(char s)
3087{
3088 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3089}
3090
3091/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3092char *check_replace_string(char *str)
3093{
3094 char *err = NULL;
3095 while (*str) {
3096 if (*str == '\\') {
3097 err = str; /* in case of a backslash, we return the pointer to it */
3098 str++;
3099 if (!*str)
3100 return err;
3101 else if (isdigit((int)*str))
3102 err = NULL;
3103 else if (*str == 'x') {
3104 str++;
3105 if (!ishex(*str))
3106 return err;
3107 str++;
3108 if (!ishex(*str))
3109 return err;
3110 err = NULL;
3111 }
3112 else {
3113 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3114 err = NULL;
3115 }
3116 }
3117 str++;
3118 }
3119 return err;
3120}
3121
3122
willy tarreau9fe663a2005-12-17 13:02:59 +01003123
willy tarreau0f7af912005-12-17 12:21:26 +01003124/*
3125 * manages the client FSM and its socket. BTW, it also tries to handle the
3126 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3127 * 0 else.
3128 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003129int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003130 int s = t->srv_state;
3131 int c = t->cli_state;
3132 struct buffer *req = t->req;
3133 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003134 int method_checked = 0;
3135 appsess *asession_temp = NULL;
3136 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003137
willy tarreau750a4722005-12-17 13:21:24 +01003138#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003139 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3140 cli_stnames[c], srv_stnames[s],
3141 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3142 t->crexpire.tv_sec, t->crexpire.tv_usec,
3143 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003144#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003145 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3146 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3147 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3148 //);
3149 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003150 /* now parse the partial (or complete) headers */
3151 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3152 char *ptr;
3153 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003154 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003155
willy tarreau5cbea6f2005-12-17 12:48:26 +01003156 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003157
willy tarreau0f7af912005-12-17 12:21:26 +01003158 /* look for the end of the current header */
3159 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3160 ptr++;
3161
willy tarreau5cbea6f2005-12-17 12:48:26 +01003162 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003163 int line, len;
3164 /* we can only get here after an end of headers */
3165 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003166
willy tarreaue39cd132005-12-17 13:00:18 +01003167 if (t->flags & SN_CLDENY) {
3168 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003169 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003170 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003171 if (!(t->flags & SN_ERR_MASK))
3172 t->flags |= SN_ERR_PRXCOND;
3173 if (!(t->flags & SN_FINST_MASK))
3174 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003175 return 1;
3176 }
3177
willy tarreau5cbea6f2005-12-17 12:48:26 +01003178 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003179 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3180 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003181 }
willy tarreau0f7af912005-12-17 12:21:26 +01003182
willy tarreau9fe663a2005-12-17 13:02:59 +01003183 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003184 if (t->cli_addr.ss_family == AF_INET) {
3185 unsigned char *pn;
3186 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3187 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3188 pn[0], pn[1], pn[2], pn[3]);
3189 buffer_replace2(req, req->h, req->h, trash, len);
3190 }
3191 else if (t->cli_addr.ss_family == AF_INET6) {
3192 char pn[INET6_ADDRSTRLEN];
3193 inet_ntop(AF_INET6,
3194 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3195 pn, sizeof(pn));
3196 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3197 buffer_replace2(req, req->h, req->h, trash, len);
3198 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003199 }
3200
willy tarreau25c4ea52005-12-18 00:49:49 +01003201 /* add a "connection: close" line if needed */
3202 if (t->proxy->options & PR_O_HTTP_CLOSE)
3203 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3204
willy tarreau982249e2005-12-18 00:57:06 +01003205 if (!memcmp(req->data, "POST ", 5)) {
3206 /* this is a POST request, which is not cacheable by default */
3207 t->flags |= SN_POST;
3208 }
willy tarreaucd878942005-12-17 13:27:43 +01003209
willy tarreau5cbea6f2005-12-17 12:48:26 +01003210 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003211 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003212
willy tarreau750a4722005-12-17 13:21:24 +01003213 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003214 /* FIXME: we'll set the client in a wait state while we try to
3215 * connect to the server. Is this really needed ? wouldn't it be
3216 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003217 //FD_CLR(t->cli_fd, StaticReadEvent);
3218 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003219
3220 /* FIXME: if we break here (as up to 1.1.23), having the client
3221 * shutdown its connection can lead to an abort further.
3222 * it's better to either return 1 or even jump directly to the
3223 * data state which will save one schedule.
3224 */
3225 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003226
3227 if (!t->proxy->clitimeout ||
3228 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3229 /* If the client has no timeout, or if the server is not ready yet,
3230 * and we know for sure that it can expire, then it's cleaner to
3231 * disable the timeout on the client side so that too low values
3232 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003233 *
3234 * FIXME-20050705: the server needs a way to re-enable this time-out
3235 * when it switches its state, otherwise a client can stay connected
3236 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003237 */
3238 tv_eternity(&t->crexpire);
3239
willy tarreau197e8ec2005-12-17 14:10:59 +01003240 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003241 }
willy tarreau0f7af912005-12-17 12:21:26 +01003242
Willy TARREAU13032e72006-03-12 17:31:45 +01003243 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3244 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003245 /* this is a partial header, let's wait for more to come */
3246 req->lr = ptr;
3247 break;
3248 }
willy tarreau0f7af912005-12-17 12:21:26 +01003249
willy tarreau5cbea6f2005-12-17 12:48:26 +01003250 /* now we know that *ptr is either \r or \n,
3251 * and that there are at least 1 char after it.
3252 */
3253 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3254 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3255 else
3256 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003257
willy tarreau5cbea6f2005-12-17 12:48:26 +01003258 /*
3259 * now we know that we have a full header ; we can do whatever
3260 * we want with these pointers :
3261 * req->h = beginning of header
3262 * ptr = end of header (first \r or \n)
3263 * req->lr = beginning of next line (next rep->h)
3264 * req->r = end of data (not used at this stage)
3265 */
willy tarreau0f7af912005-12-17 12:21:26 +01003266
willy tarreau12350152005-12-18 01:03:27 +01003267 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3268 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3269 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3270
3271 /* skip ; */
3272 request_line++;
3273
3274 /* look if we have a jsessionid */
3275
3276 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3277
3278 /* skip jsessionid= */
3279 request_line += t->proxy->appsession_name_len + 1;
3280
3281 /* First try if we allready have an appsession */
3282 asession_temp = &local_asession;
3283
3284 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3285 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3286 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3287 return 0;
3288 }
3289
3290 /* Copy the sessionid */
3291 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3292 asession_temp->sessid[t->proxy->appsession_len] = 0;
3293 asession_temp->serverid = NULL;
3294
3295 /* only do insert, if lookup fails */
3296 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3297 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3298 Alert("Not enough memory process_cli():asession:calloc().\n");
3299 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3300 return 0;
3301 }
3302 asession_temp->sessid = local_asession.sessid;
3303 asession_temp->serverid = local_asession.serverid;
3304 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003305 } /* end if (chtbl_lookup()) */
3306 else {
willy tarreau12350152005-12-18 01:03:27 +01003307 /*free wasted memory;*/
3308 pool_free_to(apools.sessid, local_asession.sessid);
3309 }
3310
3311 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3312 asession_temp->request_count++;
3313
3314#if defined(DEBUG_HASH)
3315 print_table(&(t->proxy->htbl_proxy));
3316#endif
3317
3318 if (asession_temp->serverid == NULL) {
3319 Alert("Found Application Session without matching server.\n");
3320 } else {
3321 struct server *srv = t->proxy->srv;
3322 while (srv) {
3323 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3324 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3325 /* we found the server and it's usable */
3326 t->flags &= ~SN_CK_MASK;
3327 t->flags |= SN_CK_VALID | SN_DIRECT;
3328 t->srv = srv;
3329 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003330 } else {
willy tarreau12350152005-12-18 01:03:27 +01003331 t->flags &= ~SN_CK_MASK;
3332 t->flags |= SN_CK_DOWN;
3333 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003334 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003335 srv = srv->next;
3336 }/* end while(srv) */
3337 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003338 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003339 else {
3340 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3341 }
willy tarreau598da412005-12-18 01:07:29 +01003342 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003343 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003344 else{
3345 //printf("No Methode-Header with Session-String\n");
3346 }
3347
willy tarreau8337c6b2005-12-17 13:41:01 +01003348 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003349 /* we have a complete HTTP request that we must log */
3350 int urilen;
3351
willy tarreaua1598082005-12-17 13:08:06 +01003352 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003353 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003354 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003355 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003356 if (!(t->flags & SN_ERR_MASK))
3357 t->flags |= SN_ERR_PRXCOND;
3358 if (!(t->flags & SN_FINST_MASK))
3359 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003360 return 1;
3361 }
3362
3363 urilen = ptr - req->h;
3364 if (urilen >= REQURI_LEN)
3365 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003366 memcpy(t->logs.uri, req->h, urilen);
3367 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003368
willy tarreaua1598082005-12-17 13:08:06 +01003369 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003370 sess_log(t);
3371 }
willy tarreau4302f492005-12-18 01:00:37 +01003372 else if (t->logs.logwait & LW_REQHDR) {
3373 struct cap_hdr *h;
3374 int len;
3375 for (h = t->proxy->req_cap; h; h = h->next) {
3376 if ((h->namelen + 2 <= ptr - req->h) &&
3377 (req->h[h->namelen] == ':') &&
3378 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3379
3380 if (t->req_cap[h->index] == NULL)
3381 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3382
3383 len = ptr - (req->h + h->namelen + 2);
3384 if (len > h->len)
3385 len = h->len;
3386
3387 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3388 t->req_cap[h->index][len]=0;
3389 }
3390 }
3391
3392 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003393
willy tarreau5cbea6f2005-12-17 12:48:26 +01003394 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003395
willy tarreau982249e2005-12-18 00:57:06 +01003396 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003397 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003398 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 +01003399 max = ptr - req->h;
3400 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003401 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003402 trash[len++] = '\n';
3403 write(1, trash, len);
3404 }
willy tarreau0f7af912005-12-17 12:21:26 +01003405
willy tarreau25c4ea52005-12-18 00:49:49 +01003406
3407 /* remove "connection: " if needed */
3408 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3409 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3410 delete_header = 1;
3411 }
3412
willy tarreau5cbea6f2005-12-17 12:48:26 +01003413 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003414 if (!delete_header && t->proxy->req_exp != NULL
3415 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003416 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003417 char term;
3418
3419 term = *ptr;
3420 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003421 exp = t->proxy->req_exp;
3422 do {
3423 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3424 switch (exp->action) {
3425 case ACT_ALLOW:
3426 if (!(t->flags & SN_CLDENY))
3427 t->flags |= SN_CLALLOW;
3428 break;
3429 case ACT_REPLACE:
3430 if (!(t->flags & SN_CLDENY)) {
3431 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3432 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3433 }
3434 break;
3435 case ACT_REMOVE:
3436 if (!(t->flags & SN_CLDENY))
3437 delete_header = 1;
3438 break;
3439 case ACT_DENY:
3440 if (!(t->flags & SN_CLALLOW))
3441 t->flags |= SN_CLDENY;
3442 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003443 case ACT_PASS: /* we simply don't deny this one */
3444 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003445 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003446 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003447 }
willy tarreaue39cd132005-12-17 13:00:18 +01003448 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003449 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003450 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003451
willy tarreau240afa62005-12-17 13:14:35 +01003452 /* Now look for cookies. Conforming to RFC2109, we have to support
3453 * attributes whose name begin with a '$', and associate them with
3454 * the right cookie, if we want to delete this cookie.
3455 * So there are 3 cases for each cookie read :
3456 * 1) it's a special attribute, beginning with a '$' : ignore it.
3457 * 2) it's a server id cookie that we *MAY* want to delete : save
3458 * some pointers on it (last semi-colon, beginning of cookie...)
3459 * 3) it's an application cookie : we *MAY* have to delete a previous
3460 * "special" cookie.
3461 * At the end of loop, if a "special" cookie remains, we may have to
3462 * remove it. If no application cookie persists in the header, we
3463 * *MUST* delete it
3464 */
willy tarreau12350152005-12-18 01:03:27 +01003465 if (!delete_header &&
3466 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003467 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003468 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003469 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003470 char *del_colon, *del_cookie, *colon;
3471 int app_cookies;
3472
willy tarreau5cbea6f2005-12-17 12:48:26 +01003473 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003474 colon = p1;
3475 /* del_cookie == NULL => nothing to be deleted */
3476 del_colon = del_cookie = NULL;
3477 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003478
3479 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003480 /* skip spaces and colons, but keep an eye on these ones */
3481 while (p1 < ptr) {
3482 if (*p1 == ';' || *p1 == ',')
3483 colon = p1;
3484 else if (!isspace((int)*p1))
3485 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003486 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003487 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003488
3489 if (p1 == ptr)
3490 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003491
3492 /* p1 is at the beginning of the cookie name */
3493 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003494 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003495 p2++;
3496
3497 if (p2 == ptr)
3498 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003499
3500 p3 = p2 + 1; /* skips the '=' sign */
3501 if (p3 == ptr)
3502 break;
3503
willy tarreau240afa62005-12-17 13:14:35 +01003504 p4 = p3;
3505 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003506 p4++;
3507
3508 /* here, we have the cookie name between p1 and p2,
3509 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003510 * we can process it :
3511 *
3512 * Cookie: NAME=VALUE;
3513 * | || || |
3514 * | || || +--> p4
3515 * | || |+-------> p3
3516 * | || +--------> p2
3517 * | |+------------> p1
3518 * | +-------------> colon
3519 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003520 */
3521
willy tarreau240afa62005-12-17 13:14:35 +01003522 if (*p1 == '$') {
3523 /* skip this one */
3524 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003525 else {
3526 /* first, let's see if we want to capture it */
3527 if (t->proxy->capture_name != NULL &&
3528 t->logs.cli_cookie == NULL &&
3529 (p4 - p1 >= t->proxy->capture_namelen) &&
3530 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3531 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003532
willy tarreau8337c6b2005-12-17 13:41:01 +01003533 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3534 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003535 } else {
3536 if (log_len > t->proxy->capture_len)
3537 log_len = t->proxy->capture_len;
3538 memcpy(t->logs.cli_cookie, p1, log_len);
3539 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003540 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003541 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003542
3543 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3544 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3545 /* Cool... it's the right one */
3546 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003547 char *delim;
3548
3549 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3550 * have the server ID betweek p3 and delim, and the original cookie between
3551 * delim+1 and p4. Otherwise, delim==p4 :
3552 *
3553 * Cookie: NAME=SRV~VALUE;
3554 * | || || | |
3555 * | || || | +--> p4
3556 * | || || +--------> delim
3557 * | || |+-----------> p3
3558 * | || +------------> p2
3559 * | |+----------------> p1
3560 * | +-----------------> colon
3561 * +------------------------> req->h
3562 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003563
willy tarreau0174f312005-12-18 01:02:42 +01003564 if (t->proxy->options & PR_O_COOK_PFX) {
3565 for (delim = p3; delim < p4; delim++)
3566 if (*delim == COOKIE_DELIM)
3567 break;
3568 }
3569 else
3570 delim = p4;
3571
3572
3573 /* Here, we'll look for the first running server which supports the cookie.
3574 * This allows to share a same cookie between several servers, for example
3575 * to dedicate backup servers to specific servers only.
3576 */
3577 while (srv) {
3578 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3579 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3580 /* we found the server and it's usable */
3581 t->flags &= ~SN_CK_MASK;
3582 t->flags |= SN_CK_VALID | SN_DIRECT;
3583 t->srv = srv;
3584 break;
willy tarreau12350152005-12-18 01:03:27 +01003585 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003586 /* we found a server, but it's down */
3587 t->flags &= ~SN_CK_MASK;
3588 t->flags |= SN_CK_DOWN;
3589 }
3590 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003591 srv = srv->next;
3592 }
3593
willy tarreau0174f312005-12-18 01:02:42 +01003594 if (!srv && !(t->flags & SN_CK_DOWN)) {
3595 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003596 t->flags &= ~SN_CK_MASK;
3597 t->flags |= SN_CK_INVALID;
3598 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003599
willy tarreau0174f312005-12-18 01:02:42 +01003600 /* depending on the cookie mode, we may have to either :
3601 * - delete the complete cookie if we're in insert+indirect mode, so that
3602 * the server never sees it ;
3603 * - remove the server id from the cookie value, and tag the cookie as an
3604 * application cookie so that it does not get accidentely removed later,
3605 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003606 */
willy tarreau0174f312005-12-18 01:02:42 +01003607 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3608 buffer_replace2(req, p3, delim + 1, NULL, 0);
3609 p4 -= (delim + 1 - p3);
3610 ptr -= (delim + 1 - p3);
3611 del_cookie = del_colon = NULL;
3612 app_cookies++; /* protect the header from deletion */
3613 }
3614 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003615 (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 +01003616 del_cookie = p1;
3617 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003618 }
willy tarreau12350152005-12-18 01:03:27 +01003619 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003620 /* now we know that we must keep this cookie since it's
3621 * not ours. But if we wanted to delete our cookie
3622 * earlier, we cannot remove the complete header, but we
3623 * can remove the previous block itself.
3624 */
3625 app_cookies++;
3626
3627 if (del_cookie != NULL) {
3628 buffer_replace2(req, del_cookie, p1, NULL, 0);
3629 p4 -= (p1 - del_cookie);
3630 ptr -= (p1 - del_cookie);
3631 del_cookie = del_colon = NULL;
3632 }
willy tarreau240afa62005-12-17 13:14:35 +01003633 }
willy tarreau12350152005-12-18 01:03:27 +01003634
3635 if ((t->proxy->appsession_name != NULL) &&
3636 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3637 /* first, let's see if the cookie is our appcookie*/
3638
3639 /* Cool... it's the right one */
3640
3641 asession_temp = &local_asession;
3642
3643 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3644 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3645 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3646 return 0;
3647 }
3648
3649 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3650 asession_temp->sessid[t->proxy->appsession_len] = 0;
3651 asession_temp->serverid = NULL;
3652
3653 /* only do insert, if lookup fails */
3654 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3655 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3656 Alert("Not enough memory process_cli():asession:calloc().\n");
3657 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3658 return 0;
3659 }
3660
3661 asession_temp->sessid = local_asession.sessid;
3662 asession_temp->serverid = local_asession.serverid;
3663 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3664 }
3665 else{
3666 /* free wasted memory */
3667 pool_free_to(apools.sessid, local_asession.sessid);
3668 }
3669
3670 if (asession_temp->serverid == NULL) {
3671 Alert("Found Application Session without matching server.\n");
3672 } else {
3673 struct server *srv = t->proxy->srv;
3674 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003675 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003676 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3677 /* we found the server and it's usable */
3678 t->flags &= ~SN_CK_MASK;
3679 t->flags |= SN_CK_VALID | SN_DIRECT;
3680 t->srv = srv;
3681 break;
3682 } else {
3683 t->flags &= ~SN_CK_MASK;
3684 t->flags |= SN_CK_DOWN;
3685 }
3686 }
3687 srv = srv->next;
3688 }/* end while(srv) */
3689 }/* end else if server == NULL */
3690
3691 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003692 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003693 }
willy tarreau240afa62005-12-17 13:14:35 +01003694
willy tarreau5cbea6f2005-12-17 12:48:26 +01003695 /* we'll have to look for another cookie ... */
3696 p1 = p4;
3697 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003698
3699 /* There's no more cookie on this line.
3700 * We may have marked the last one(s) for deletion.
3701 * We must do this now in two ways :
3702 * - if there is no app cookie, we simply delete the header ;
3703 * - if there are app cookies, we must delete the end of the
3704 * string properly, including the colon/semi-colon before
3705 * the cookie name.
3706 */
3707 if (del_cookie != NULL) {
3708 if (app_cookies) {
3709 buffer_replace2(req, del_colon, ptr, NULL, 0);
3710 /* WARNING! <ptr> becomes invalid for now. If some code
3711 * below needs to rely on it before the end of the global
3712 * header loop, we need to correct it with this code :
3713 * ptr = del_colon;
3714 */
3715 }
3716 else
3717 delete_header = 1;
3718 }
3719 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003720
3721 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003722 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003723 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003724 }
willy tarreau240afa62005-12-17 13:14:35 +01003725 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3726
willy tarreau5cbea6f2005-12-17 12:48:26 +01003727 req->h = req->lr;
3728 } /* while (req->lr < req->r) */
3729
3730 /* end of header processing (even if incomplete) */
3731
willy tarreauef900ab2005-12-17 12:52:52 +01003732 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3733 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3734 * full. We cannot loop here since event_cli_read will disable it only if
3735 * req->l == rlim-data
3736 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003737 FD_SET(t->cli_fd, StaticReadEvent);
3738 if (t->proxy->clitimeout)
3739 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3740 else
3741 tv_eternity(&t->crexpire);
3742 }
3743
willy tarreaue39cd132005-12-17 13:00:18 +01003744 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003745 * won't be able to free more later, so the session will never terminate.
3746 */
willy tarreaue39cd132005-12-17 13:00:18 +01003747 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003748 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003749 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003750 if (!(t->flags & SN_ERR_MASK))
3751 t->flags |= SN_ERR_PRXCOND;
3752 if (!(t->flags & SN_FINST_MASK))
3753 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003754 return 1;
3755 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003756 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003757 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003758 tv_eternity(&t->crexpire);
3759 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003760 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003761 if (!(t->flags & SN_ERR_MASK))
3762 t->flags |= SN_ERR_CLICL;
3763 if (!(t->flags & SN_FINST_MASK))
3764 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003765 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003766 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003767 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3768
3769 /* read timeout : give up with an error message.
3770 */
3771 t->logs.status = 408;
3772 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003773 if (!(t->flags & SN_ERR_MASK))
3774 t->flags |= SN_ERR_CLITO;
3775 if (!(t->flags & SN_FINST_MASK))
3776 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003777 return 1;
3778 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003779
3780 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003781 }
3782 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003783 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003784 /* FIXME: this error handling is partly buggy because we always report
3785 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3786 * or HEADER phase. BTW, it's not logical to expire the client while
3787 * we're waiting for the server to connect.
3788 */
willy tarreau0f7af912005-12-17 12:21:26 +01003789 /* read or write error */
3790 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003791 tv_eternity(&t->crexpire);
3792 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003793 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003794 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003795 if (!(t->flags & SN_ERR_MASK))
3796 t->flags |= SN_ERR_CLICL;
3797 if (!(t->flags & SN_FINST_MASK))
3798 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003799 return 1;
3800 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003801 /* last read, or end of server write */
3802 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003803 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003804 tv_eternity(&t->crexpire);
3805 shutdown(t->cli_fd, SHUT_RD);
3806 t->cli_state = CL_STSHUTR;
3807 return 1;
3808 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003809 /* last server read and buffer empty */
3810 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003811 FD_CLR(t->cli_fd, StaticWriteEvent);
3812 tv_eternity(&t->cwexpire);
3813 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003814 /* We must ensure that the read part is still alive when switching
3815 * to shutw */
3816 FD_SET(t->cli_fd, StaticReadEvent);
3817 if (t->proxy->clitimeout)
3818 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003819 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003820 //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 +01003821 return 1;
3822 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003823 /* read timeout */
3824 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3825 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003826 tv_eternity(&t->crexpire);
3827 shutdown(t->cli_fd, SHUT_RD);
3828 t->cli_state = CL_STSHUTR;
3829 if (!(t->flags & SN_ERR_MASK))
3830 t->flags |= SN_ERR_CLITO;
3831 if (!(t->flags & SN_FINST_MASK))
3832 t->flags |= SN_FINST_D;
3833 return 1;
3834 }
3835 /* write timeout */
3836 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3837 FD_CLR(t->cli_fd, StaticWriteEvent);
3838 tv_eternity(&t->cwexpire);
3839 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003840 /* We must ensure that the read part is still alive when switching
3841 * to shutw */
3842 FD_SET(t->cli_fd, StaticReadEvent);
3843 if (t->proxy->clitimeout)
3844 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3845
willy tarreau036e1ce2005-12-17 13:46:33 +01003846 t->cli_state = CL_STSHUTW;
3847 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003848 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003849 if (!(t->flags & SN_FINST_MASK))
3850 t->flags |= SN_FINST_D;
3851 return 1;
3852 }
willy tarreau0f7af912005-12-17 12:21:26 +01003853
willy tarreauc58fc692005-12-17 14:13:08 +01003854 if (req->l >= req->rlim - req->data) {
3855 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003856 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003857 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003858 FD_CLR(t->cli_fd, StaticReadEvent);
3859 tv_eternity(&t->crexpire);
3860 }
3861 }
3862 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003863 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003864 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3865 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003866 if (!t->proxy->clitimeout ||
3867 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3868 /* If the client has no timeout, or if the server not ready yet, and we
3869 * know for sure that it can expire, then it's cleaner to disable the
3870 * timeout on the client side so that too low values cannot make the
3871 * sessions abort too early.
3872 */
willy tarreau0f7af912005-12-17 12:21:26 +01003873 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003874 else
3875 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003876 }
3877 }
3878
3879 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003880 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003881 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3882 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3883 tv_eternity(&t->cwexpire);
3884 }
3885 }
3886 else { /* buffer not empty */
3887 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3888 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003889 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003890 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003891 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3892 t->crexpire = t->cwexpire;
3893 }
willy tarreau0f7af912005-12-17 12:21:26 +01003894 else
3895 tv_eternity(&t->cwexpire);
3896 }
3897 }
3898 return 0; /* other cases change nothing */
3899 }
3900 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003901 if (t->res_cw == RES_ERROR) {
3902 tv_eternity(&t->cwexpire);
3903 fd_delete(t->cli_fd);
3904 t->cli_state = CL_STCLOSE;
3905 if (!(t->flags & SN_ERR_MASK))
3906 t->flags |= SN_ERR_CLICL;
3907 if (!(t->flags & SN_FINST_MASK))
3908 t->flags |= SN_FINST_D;
3909 return 1;
3910 }
3911 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003912 tv_eternity(&t->cwexpire);
3913 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003914 t->cli_state = CL_STCLOSE;
3915 return 1;
3916 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003917 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3918 tv_eternity(&t->cwexpire);
3919 fd_delete(t->cli_fd);
3920 t->cli_state = CL_STCLOSE;
3921 if (!(t->flags & SN_ERR_MASK))
3922 t->flags |= SN_ERR_CLITO;
3923 if (!(t->flags & SN_FINST_MASK))
3924 t->flags |= SN_FINST_D;
3925 return 1;
3926 }
willy tarreau0f7af912005-12-17 12:21:26 +01003927 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003928 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003929 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3930 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3931 tv_eternity(&t->cwexpire);
3932 }
3933 }
3934 else { /* buffer not empty */
3935 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3936 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003937 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003938 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003939 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3940 t->crexpire = t->cwexpire;
3941 }
willy tarreau0f7af912005-12-17 12:21:26 +01003942 else
3943 tv_eternity(&t->cwexpire);
3944 }
3945 }
3946 return 0;
3947 }
3948 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003949 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003950 tv_eternity(&t->crexpire);
3951 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003952 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003953 if (!(t->flags & SN_ERR_MASK))
3954 t->flags |= SN_ERR_CLICL;
3955 if (!(t->flags & SN_FINST_MASK))
3956 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003957 return 1;
3958 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003959 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3960 tv_eternity(&t->crexpire);
3961 fd_delete(t->cli_fd);
3962 t->cli_state = CL_STCLOSE;
3963 return 1;
3964 }
3965 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3966 tv_eternity(&t->crexpire);
3967 fd_delete(t->cli_fd);
3968 t->cli_state = CL_STCLOSE;
3969 if (!(t->flags & SN_ERR_MASK))
3970 t->flags |= SN_ERR_CLITO;
3971 if (!(t->flags & SN_FINST_MASK))
3972 t->flags |= SN_FINST_D;
3973 return 1;
3974 }
willy tarreauef900ab2005-12-17 12:52:52 +01003975 else if (req->l >= req->rlim - req->data) {
3976 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01003977
3978 /* FIXME-20050705: is it possible for a client to maintain a session
3979 * after the timeout by sending more data after it receives a close ?
3980 */
3981
willy tarreau0f7af912005-12-17 12:21:26 +01003982 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003983 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003984 FD_CLR(t->cli_fd, StaticReadEvent);
3985 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003986 //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 +01003987 }
3988 }
3989 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003990 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003991 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3992 FD_SET(t->cli_fd, StaticReadEvent);
3993 if (t->proxy->clitimeout)
3994 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3995 else
3996 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003997 //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 +01003998 }
3999 }
4000 return 0;
4001 }
4002 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004003 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004004 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004005 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 +01004006 write(1, trash, len);
4007 }
4008 return 0;
4009 }
4010 return 0;
4011}
4012
4013
4014/*
4015 * manages the server FSM and its socket. It returns 1 if a state has changed
4016 * (and a resync may be needed), 0 else.
4017 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004018int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004019 int s = t->srv_state;
4020 int c = t->cli_state;
4021 struct buffer *req = t->req;
4022 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004023 appsess *asession_temp = NULL;
4024 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004025 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004026
willy tarreau750a4722005-12-17 13:21:24 +01004027#ifdef DEBUG_FULL
4028 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4029#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004030 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4031 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4032 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4033 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004034 if (s == SV_STIDLE) {
4035 if (c == CL_STHEADERS)
4036 return 0; /* stay in idle, waiting for data to reach the client side */
4037 else if (c == CL_STCLOSE ||
4038 c == CL_STSHUTW ||
4039 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4040 tv_eternity(&t->cnexpire);
4041 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004042 if (!(t->flags & SN_ERR_MASK))
4043 t->flags |= SN_ERR_CLICL;
4044 if (!(t->flags & SN_FINST_MASK))
4045 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004046 return 1;
4047 }
4048 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01004049 /* initiate a connection to the server */
4050 conn_err = connect_server(t);
4051 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004052 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4053 t->srv_state = SV_STCONN;
4054 }
4055 else { /* try again */
4056 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004057 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004058 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004059 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004060 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4061 t->flags &= ~SN_CK_MASK;
4062 t->flags |= SN_CK_DOWN;
4063 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004064 }
4065
willy tarreaub1285d52005-12-18 01:20:14 +01004066 conn_err = connect_server(t);
4067 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004068 t->srv_state = SV_STCONN;
4069 break;
4070 }
4071 }
4072 if (t->conn_retries < 0) {
4073 /* if conn_retries < 0 or other error, let's abort */
4074 tv_eternity(&t->cnexpire);
4075 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004076 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004077 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004078 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004079 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004080 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004081 if (!(t->flags & SN_FINST_MASK))
4082 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004083 }
4084 }
4085 return 1;
4086 }
4087 }
4088 else if (s == SV_STCONN) { /* connection in progress */
4089 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004090 //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 +01004091 return 0; /* nothing changed */
4092 }
4093 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4094 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4095 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004096 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004097 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004098 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004099 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004100 if (t->conn_retries >= 0) {
4101 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004102 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004103 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004104 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4105 t->flags &= ~SN_CK_MASK;
4106 t->flags |= SN_CK_DOWN;
4107 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004108 }
willy tarreaub1285d52005-12-18 01:20:14 +01004109 conn_err = connect_server(t);
4110 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004111 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004112 }
willy tarreaub1285d52005-12-18 01:20:14 +01004113 else if (t->res_sw == RES_SILENT)
4114 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4115 else
4116 conn_err = SN_ERR_SRVCL; // it was a connect error.
4117
willy tarreau0f7af912005-12-17 12:21:26 +01004118 /* if conn_retries < 0 or other error, let's abort */
4119 tv_eternity(&t->cnexpire);
4120 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004121 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004122 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004123 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004124 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004125 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004126 if (!(t->flags & SN_FINST_MASK))
4127 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004128 return 1;
4129 }
4130 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004131 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004132
willy tarreau0f7af912005-12-17 12:21:26 +01004133 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004134 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004135 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004136 tv_eternity(&t->swexpire);
4137 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004138 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004139 if (t->proxy->srvtimeout) {
4140 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4141 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4142 t->srexpire = t->swexpire;
4143 }
4144 else
4145 tv_eternity(&t->swexpire);
4146 }
willy tarreau0f7af912005-12-17 12:21:26 +01004147
4148 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4149 FD_SET(t->srv_fd, StaticReadEvent);
4150 if (t->proxy->srvtimeout)
4151 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4152 else
4153 tv_eternity(&t->srexpire);
4154
4155 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004156 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004157
4158 /* if the user wants to log as soon as possible, without counting
4159 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004160 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004161 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4162 sess_log(t);
4163 }
willy tarreau0f7af912005-12-17 12:21:26 +01004164 }
willy tarreauef900ab2005-12-17 12:52:52 +01004165 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004166 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004167 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4168 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004169 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004170 return 1;
4171 }
4172 }
4173 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004174 /* now parse the partial (or complete) headers */
4175 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4176 char *ptr;
4177 int delete_header;
4178
4179 ptr = rep->lr;
4180
4181 /* look for the end of the current header */
4182 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4183 ptr++;
4184
4185 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004186 int line, len;
4187
4188 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004189
4190 /* first, we'll block if security checks have caught nasty things */
4191 if (t->flags & SN_CACHEABLE) {
4192 if ((t->flags & SN_CACHE_COOK) &&
4193 (t->flags & SN_SCK_ANY) &&
4194 (t->proxy->options & PR_O_CHK_CACHE)) {
4195
4196 /* we're in presence of a cacheable response containing
4197 * a set-cookie header. We'll block it as requested by
4198 * the 'checkcache' option, and send an alert.
4199 */
4200 tv_eternity(&t->srexpire);
4201 tv_eternity(&t->swexpire);
4202 fd_delete(t->srv_fd);
4203 t->srv_state = SV_STCLOSE;
4204 t->logs.status = 502;
4205 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4206 if (!(t->flags & SN_ERR_MASK))
4207 t->flags |= SN_ERR_PRXCOND;
4208 if (!(t->flags & SN_FINST_MASK))
4209 t->flags |= SN_FINST_H;
4210
4211 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4212 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4213
4214 return 1;
4215 }
4216 }
4217
willy tarreau982249e2005-12-18 00:57:06 +01004218 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4219 if (t->flags & SN_SVDENY) {
4220 tv_eternity(&t->srexpire);
4221 tv_eternity(&t->swexpire);
4222 fd_delete(t->srv_fd);
4223 t->srv_state = SV_STCLOSE;
4224 t->logs.status = 502;
4225 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4226 if (!(t->flags & SN_ERR_MASK))
4227 t->flags |= SN_ERR_PRXCOND;
4228 if (!(t->flags & SN_FINST_MASK))
4229 t->flags |= SN_FINST_H;
4230 return 1;
4231 }
4232
willy tarreau5cbea6f2005-12-17 12:48:26 +01004233 /* we'll have something else to do here : add new headers ... */
4234
willy tarreaucd878942005-12-17 13:27:43 +01004235 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4236 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004237 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004238 * insert a set-cookie here, except if we want to insert only on POST
4239 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004240 */
willy tarreau750a4722005-12-17 13:21:24 +01004241 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004242 t->proxy->cookie_name,
4243 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004244
willy tarreau036e1ce2005-12-17 13:46:33 +01004245 t->flags |= SN_SCK_INSERTED;
4246
willy tarreau750a4722005-12-17 13:21:24 +01004247 /* Here, we will tell an eventual cache on the client side that we don't
4248 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4249 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4250 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4251 */
willy tarreau240afa62005-12-17 13:14:35 +01004252 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004253 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4254 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004255
4256 if (rep->data + rep->l < rep->h)
4257 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4258 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004259 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004260 }
4261
4262 /* headers to be added */
4263 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004264 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4265 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004266 }
4267
willy tarreau25c4ea52005-12-18 00:49:49 +01004268 /* add a "connection: close" line if needed */
4269 if (t->proxy->options & PR_O_HTTP_CLOSE)
4270 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4271
willy tarreau5cbea6f2005-12-17 12:48:26 +01004272 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004273 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004274 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004275
Willy TARREAU767ba712006-03-01 22:40:50 +01004276 /* client connection already closed or option 'httpclose' required :
4277 * we close the server's outgoing connection right now.
4278 */
4279 if ((req->l == 0) &&
4280 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4281 FD_CLR(t->srv_fd, StaticWriteEvent);
4282 tv_eternity(&t->swexpire);
4283
4284 /* We must ensure that the read part is still alive when switching
4285 * to shutw */
4286 FD_SET(t->srv_fd, StaticReadEvent);
4287 if (t->proxy->srvtimeout)
4288 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4289
4290 shutdown(t->srv_fd, SHUT_WR);
4291 t->srv_state = SV_STSHUTW;
4292 }
4293
willy tarreau25c4ea52005-12-18 00:49:49 +01004294 /* if the user wants to log as soon as possible, without counting
4295 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004296 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004297 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4298 t->logs.bytes = rep->h - rep->data;
4299 sess_log(t);
4300 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004301 break;
4302 }
4303
4304 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4305 if (ptr > rep->r - 2) {
4306 /* this is a partial header, let's wait for more to come */
4307 rep->lr = ptr;
4308 break;
4309 }
4310
4311 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4312 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4313
4314 /* now we know that *ptr is either \r or \n,
4315 * and that there are at least 1 char after it.
4316 */
4317 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4318 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4319 else
4320 rep->lr = ptr + 2; /* \r\n or \n\r */
4321
4322 /*
4323 * now we know that we have a full header ; we can do whatever
4324 * we want with these pointers :
4325 * rep->h = beginning of header
4326 * ptr = end of header (first \r or \n)
4327 * rep->lr = beginning of next line (next rep->h)
4328 * rep->r = end of data (not used at this stage)
4329 */
4330
willy tarreaua1598082005-12-17 13:08:06 +01004331
willy tarreau982249e2005-12-18 00:57:06 +01004332 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004333 t->logs.logwait &= ~LW_RESP;
4334 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004335 switch (t->logs.status) {
4336 case 200:
4337 case 203:
4338 case 206:
4339 case 300:
4340 case 301:
4341 case 410:
4342 /* RFC2616 @13.4:
4343 * "A response received with a status code of
4344 * 200, 203, 206, 300, 301 or 410 MAY be stored
4345 * by a cache (...) unless a cache-control
4346 * directive prohibits caching."
4347 *
4348 * RFC2616 @9.5: POST method :
4349 * "Responses to this method are not cacheable,
4350 * unless the response includes appropriate
4351 * Cache-Control or Expires header fields."
4352 */
4353 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4354 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4355 break;
4356 default:
4357 break;
4358 }
willy tarreau4302f492005-12-18 01:00:37 +01004359 }
4360 else if (t->logs.logwait & LW_RSPHDR) {
4361 struct cap_hdr *h;
4362 int len;
4363 for (h = t->proxy->rsp_cap; h; h = h->next) {
4364 if ((h->namelen + 2 <= ptr - rep->h) &&
4365 (rep->h[h->namelen] == ':') &&
4366 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4367
4368 if (t->rsp_cap[h->index] == NULL)
4369 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4370
4371 len = ptr - (rep->h + h->namelen + 2);
4372 if (len > h->len)
4373 len = h->len;
4374
4375 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4376 t->rsp_cap[h->index][len]=0;
4377 }
4378 }
4379
willy tarreaua1598082005-12-17 13:08:06 +01004380 }
4381
willy tarreau5cbea6f2005-12-17 12:48:26 +01004382 delete_header = 0;
4383
willy tarreau982249e2005-12-18 00:57:06 +01004384 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004385 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004386 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 +01004387 max = ptr - rep->h;
4388 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004389 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004390 trash[len++] = '\n';
4391 write(1, trash, len);
4392 }
4393
willy tarreau25c4ea52005-12-18 00:49:49 +01004394 /* remove "connection: " if needed */
4395 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4396 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4397 delete_header = 1;
4398 }
4399
willy tarreau5cbea6f2005-12-17 12:48:26 +01004400 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004401 if (!delete_header && t->proxy->rsp_exp != NULL
4402 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004403 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004404 char term;
4405
4406 term = *ptr;
4407 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004408 exp = t->proxy->rsp_exp;
4409 do {
4410 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4411 switch (exp->action) {
4412 case ACT_ALLOW:
4413 if (!(t->flags & SN_SVDENY))
4414 t->flags |= SN_SVALLOW;
4415 break;
4416 case ACT_REPLACE:
4417 if (!(t->flags & SN_SVDENY)) {
4418 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4419 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4420 }
4421 break;
4422 case ACT_REMOVE:
4423 if (!(t->flags & SN_SVDENY))
4424 delete_header = 1;
4425 break;
4426 case ACT_DENY:
4427 if (!(t->flags & SN_SVALLOW))
4428 t->flags |= SN_SVDENY;
4429 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004430 case ACT_PASS: /* we simply don't deny this one */
4431 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004432 }
4433 break;
4434 }
willy tarreaue39cd132005-12-17 13:00:18 +01004435 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004436 *ptr = term; /* restore the string terminator */
4437 }
4438
willy tarreau97f58572005-12-18 00:53:44 +01004439 /* check for cache-control: or pragma: headers */
4440 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4441 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4442 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4443 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4444 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004445 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004446 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4447 else {
4448 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004449 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004450 t->flags &= ~SN_CACHE_COOK;
4451 }
4452 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004453 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004454 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004455 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004456 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4457 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004458 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004459 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004460 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4461 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4462 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4463 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4464 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4465 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004466 }
4467 }
4468 }
4469
willy tarreau5cbea6f2005-12-17 12:48:26 +01004470 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004471 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004472 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004473 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004474 char *p1, *p2, *p3, *p4;
4475
willy tarreau97f58572005-12-18 00:53:44 +01004476 t->flags |= SN_SCK_ANY;
4477
willy tarreau5cbea6f2005-12-17 12:48:26 +01004478 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4479
4480 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004481 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004482 p1++;
4483
4484 if (p1 == ptr || *p1 == ';') /* end of cookie */
4485 break;
4486
4487 /* p1 is at the beginning of the cookie name */
4488 p2 = p1;
4489
4490 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4491 p2++;
4492
4493 if (p2 == ptr || *p2 == ';') /* next cookie */
4494 break;
4495
4496 p3 = p2 + 1; /* skips the '=' sign */
4497 if (p3 == ptr)
4498 break;
4499
4500 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004501 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004502 p4++;
4503
4504 /* here, we have the cookie name between p1 and p2,
4505 * and its value between p3 and p4.
4506 * we can process it.
4507 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004508
4509 /* first, let's see if we want to capture it */
4510 if (t->proxy->capture_name != NULL &&
4511 t->logs.srv_cookie == NULL &&
4512 (p4 - p1 >= t->proxy->capture_namelen) &&
4513 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4514 int log_len = p4 - p1;
4515
4516 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4517 Alert("HTTP logging : out of memory.\n");
4518 }
4519
4520 if (log_len > t->proxy->capture_len)
4521 log_len = t->proxy->capture_len;
4522 memcpy(t->logs.srv_cookie, p1, log_len);
4523 t->logs.srv_cookie[log_len] = 0;
4524 }
4525
4526 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4527 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004528 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004529 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004530
4531 /* If the cookie is in insert mode on a known server, we'll delete
4532 * this occurrence because we'll insert another one later.
4533 * We'll delete it too if the "indirect" option is set and we're in
4534 * a direct access. */
4535 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004536 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004537 /* this header must be deleted */
4538 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004539 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004540 }
4541 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4542 /* replace bytes p3->p4 with the cookie name associated
4543 * with this server since we know it.
4544 */
4545 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004546 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004547 }
willy tarreau0174f312005-12-18 01:02:42 +01004548 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4549 /* insert the cookie name associated with this server
4550 * before existing cookie, and insert a delimitor between them..
4551 */
4552 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4553 p3[t->srv->cklen] = COOKIE_DELIM;
4554 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4555 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004556 break;
4557 }
willy tarreau12350152005-12-18 01:03:27 +01004558
4559 /* first, let's see if the cookie is our appcookie*/
4560 if ((t->proxy->appsession_name != NULL) &&
4561 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4562
4563 /* Cool... it's the right one */
4564
willy tarreaub952e1d2005-12-18 01:31:20 +01004565 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004566 asession_temp = &local_asession;
4567
willy tarreaub952e1d2005-12-18 01:31:20 +01004568 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004569 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4570 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4571 }
4572 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4573 asession_temp->sessid[t->proxy->appsession_len] = 0;
4574 asession_temp->serverid = NULL;
4575
4576 /* only do insert, if lookup fails */
4577 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4578 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4579 Alert("Not enought Memory process_srv():asession:calloc().\n");
4580 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4581 return 0;
4582 }
4583 asession_temp->sessid = local_asession.sessid;
4584 asession_temp->serverid = local_asession.serverid;
4585 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004586 }/* end if (chtbl_lookup()) */
4587 else {
willy tarreau12350152005-12-18 01:03:27 +01004588 /* free wasted memory */
4589 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004590 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004591
willy tarreaub952e1d2005-12-18 01:31:20 +01004592 if (asession_temp->serverid == NULL) {
4593 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004594 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4595 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4596 }
4597 asession_temp->serverid[0] = '\0';
4598 }
4599
willy tarreaub952e1d2005-12-18 01:31:20 +01004600 if (asession_temp->serverid[0] == '\0')
4601 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004602
4603 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4604
4605#if defined(DEBUG_HASH)
4606 print_table(&(t->proxy->htbl_proxy));
4607#endif
4608 break;
4609 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004610 else {
4611 // fprintf(stderr,"Ignoring unknown cookie : ");
4612 // write(2, p1, p2-p1);
4613 // fprintf(stderr," = ");
4614 // write(2, p3, p4-p3);
4615 // fprintf(stderr,"\n");
4616 }
4617 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4618 } /* we're now at the end of the cookie value */
4619 } /* end of cookie processing */
4620
willy tarreau97f58572005-12-18 00:53:44 +01004621 /* check for any set-cookie in case we check for cacheability */
4622 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4623 (t->proxy->options & PR_O_CHK_CACHE) &&
4624 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4625 t->flags |= SN_SCK_ANY;
4626 }
4627
willy tarreau5cbea6f2005-12-17 12:48:26 +01004628 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004629 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004630 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004631
willy tarreau5cbea6f2005-12-17 12:48:26 +01004632 rep->h = rep->lr;
4633 } /* while (rep->lr < rep->r) */
4634
4635 /* end of header processing (even if incomplete) */
4636
willy tarreauef900ab2005-12-17 12:52:52 +01004637 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4638 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4639 * full. We cannot loop here since event_srv_read will disable it only if
4640 * rep->l == rlim-data
4641 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004642 FD_SET(t->srv_fd, StaticReadEvent);
4643 if (t->proxy->srvtimeout)
4644 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4645 else
4646 tv_eternity(&t->srexpire);
4647 }
willy tarreau0f7af912005-12-17 12:21:26 +01004648
willy tarreau8337c6b2005-12-17 13:41:01 +01004649 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004650 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004651 tv_eternity(&t->srexpire);
4652 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004653 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004654 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004655 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004656 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004657 if (!(t->flags & SN_ERR_MASK))
4658 t->flags |= SN_ERR_SRVCL;
4659 if (!(t->flags & SN_FINST_MASK))
4660 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004661 return 1;
4662 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004663 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004664 * since we are in header mode, if there's no space left for headers, we
4665 * won't be able to free more later, so the session will never terminate.
4666 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004667 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 +01004668 FD_CLR(t->srv_fd, StaticReadEvent);
4669 tv_eternity(&t->srexpire);
4670 shutdown(t->srv_fd, SHUT_RD);
4671 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004672 //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 +01004673 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004674 }
4675 /* read timeout : return a 504 to the client.
4676 */
4677 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4678 tv_eternity(&t->srexpire);
4679 tv_eternity(&t->swexpire);
4680 fd_delete(t->srv_fd);
4681 t->srv_state = SV_STCLOSE;
4682 t->logs.status = 504;
4683 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004684 if (!(t->flags & SN_ERR_MASK))
4685 t->flags |= SN_ERR_SRVTO;
4686 if (!(t->flags & SN_FINST_MASK))
4687 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004688 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004689
4690 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004691 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004692 /* FIXME!!! here, we don't want to switch to SHUTW if the
4693 * client shuts read too early, because we may still have
4694 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004695 * The side-effect is that if the client completely closes its
4696 * connection during SV_STHEADER, the connection to the server
4697 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004698 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004699 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004700 FD_CLR(t->srv_fd, StaticWriteEvent);
4701 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004702
4703 /* We must ensure that the read part is still alive when switching
4704 * to shutw */
4705 FD_SET(t->srv_fd, StaticReadEvent);
4706 if (t->proxy->srvtimeout)
4707 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4708
willy tarreau0f7af912005-12-17 12:21:26 +01004709 shutdown(t->srv_fd, SHUT_WR);
4710 t->srv_state = SV_STSHUTW;
4711 return 1;
4712 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004713 /* write timeout */
4714 /* FIXME!!! here, we don't want to switch to SHUTW if the
4715 * client shuts read too early, because we may still have
4716 * some work to do on the headers.
4717 */
4718 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4719 FD_CLR(t->srv_fd, StaticWriteEvent);
4720 tv_eternity(&t->swexpire);
4721 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004722 /* We must ensure that the read part is still alive when switching
4723 * to shutw */
4724 FD_SET(t->srv_fd, StaticReadEvent);
4725 if (t->proxy->srvtimeout)
4726 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4727
4728 /* We must ensure that the read part is still alive when switching
4729 * to shutw */
4730 FD_SET(t->srv_fd, StaticReadEvent);
4731 if (t->proxy->srvtimeout)
4732 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4733
willy tarreau036e1ce2005-12-17 13:46:33 +01004734 t->srv_state = SV_STSHUTW;
4735 if (!(t->flags & SN_ERR_MASK))
4736 t->flags |= SN_ERR_SRVTO;
4737 if (!(t->flags & SN_FINST_MASK))
4738 t->flags |= SN_FINST_H;
4739 return 1;
4740 }
willy tarreau0f7af912005-12-17 12:21:26 +01004741
4742 if (req->l == 0) {
4743 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4744 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4745 tv_eternity(&t->swexpire);
4746 }
4747 }
4748 else { /* client buffer not empty */
4749 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4750 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004751 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004752 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004753 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4754 t->srexpire = t->swexpire;
4755 }
willy tarreau0f7af912005-12-17 12:21:26 +01004756 else
4757 tv_eternity(&t->swexpire);
4758 }
4759 }
4760
willy tarreau5cbea6f2005-12-17 12:48:26 +01004761 /* be nice with the client side which would like to send a complete header
4762 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4763 * would read all remaining data at once ! The client should not write past rep->lr
4764 * when the server is in header state.
4765 */
4766 //return header_processed;
4767 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004768 }
4769 else if (s == SV_STDATA) {
4770 /* read or write error */
4771 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004772 tv_eternity(&t->srexpire);
4773 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004774 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004775 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004776 if (!(t->flags & SN_ERR_MASK))
4777 t->flags |= SN_ERR_SRVCL;
4778 if (!(t->flags & SN_FINST_MASK))
4779 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004780 return 1;
4781 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004782 /* last read, or end of client write */
4783 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004784 FD_CLR(t->srv_fd, StaticReadEvent);
4785 tv_eternity(&t->srexpire);
4786 shutdown(t->srv_fd, SHUT_RD);
4787 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004788 //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 +01004789 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004790 }
4791 /* end of client read and no more data to send */
4792 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4793 FD_CLR(t->srv_fd, StaticWriteEvent);
4794 tv_eternity(&t->swexpire);
4795 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004796 /* We must ensure that the read part is still alive when switching
4797 * to shutw */
4798 FD_SET(t->srv_fd, StaticReadEvent);
4799 if (t->proxy->srvtimeout)
4800 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4801
willy tarreaua41a8b42005-12-17 14:02:24 +01004802 t->srv_state = SV_STSHUTW;
4803 return 1;
4804 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004805 /* read timeout */
4806 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4807 FD_CLR(t->srv_fd, StaticReadEvent);
4808 tv_eternity(&t->srexpire);
4809 shutdown(t->srv_fd, SHUT_RD);
4810 t->srv_state = SV_STSHUTR;
4811 if (!(t->flags & SN_ERR_MASK))
4812 t->flags |= SN_ERR_SRVTO;
4813 if (!(t->flags & SN_FINST_MASK))
4814 t->flags |= SN_FINST_D;
4815 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004816 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004817 /* write timeout */
4818 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004819 FD_CLR(t->srv_fd, StaticWriteEvent);
4820 tv_eternity(&t->swexpire);
4821 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004822 /* We must ensure that the read part is still alive when switching
4823 * to shutw */
4824 FD_SET(t->srv_fd, StaticReadEvent);
4825 if (t->proxy->srvtimeout)
4826 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004827 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004828 if (!(t->flags & SN_ERR_MASK))
4829 t->flags |= SN_ERR_SRVTO;
4830 if (!(t->flags & SN_FINST_MASK))
4831 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004832 return 1;
4833 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004834
4835 /* recompute request time-outs */
4836 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004837 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4838 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4839 tv_eternity(&t->swexpire);
4840 }
4841 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004842 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004843 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4844 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004845 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004846 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004847 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4848 t->srexpire = t->swexpire;
4849 }
willy tarreau0f7af912005-12-17 12:21:26 +01004850 else
4851 tv_eternity(&t->swexpire);
4852 }
4853 }
4854
willy tarreaub1ff9db2005-12-17 13:51:03 +01004855 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004856 if (rep->l == BUFSIZE) { /* no room to read more data */
4857 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4858 FD_CLR(t->srv_fd, StaticReadEvent);
4859 tv_eternity(&t->srexpire);
4860 }
4861 }
4862 else {
4863 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4864 FD_SET(t->srv_fd, StaticReadEvent);
4865 if (t->proxy->srvtimeout)
4866 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4867 else
4868 tv_eternity(&t->srexpire);
4869 }
4870 }
4871
4872 return 0; /* other cases change nothing */
4873 }
4874 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004875 if (t->res_sw == RES_ERROR) {
4876 //FD_CLR(t->srv_fd, StaticWriteEvent);
4877 tv_eternity(&t->swexpire);
4878 fd_delete(t->srv_fd);
4879 //close(t->srv_fd);
4880 t->srv_state = SV_STCLOSE;
4881 if (!(t->flags & SN_ERR_MASK))
4882 t->flags |= SN_ERR_SRVCL;
4883 if (!(t->flags & SN_FINST_MASK))
4884 t->flags |= SN_FINST_D;
4885 return 1;
4886 }
4887 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004888 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004889 tv_eternity(&t->swexpire);
4890 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004891 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004892 t->srv_state = SV_STCLOSE;
4893 return 1;
4894 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004895 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4896 //FD_CLR(t->srv_fd, StaticWriteEvent);
4897 tv_eternity(&t->swexpire);
4898 fd_delete(t->srv_fd);
4899 //close(t->srv_fd);
4900 t->srv_state = SV_STCLOSE;
4901 if (!(t->flags & SN_ERR_MASK))
4902 t->flags |= SN_ERR_SRVTO;
4903 if (!(t->flags & SN_FINST_MASK))
4904 t->flags |= SN_FINST_D;
4905 return 1;
4906 }
willy tarreau0f7af912005-12-17 12:21:26 +01004907 else if (req->l == 0) {
4908 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4909 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4910 tv_eternity(&t->swexpire);
4911 }
4912 }
4913 else { /* buffer not empty */
4914 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4915 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004916 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004917 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004918 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4919 t->srexpire = t->swexpire;
4920 }
willy tarreau0f7af912005-12-17 12:21:26 +01004921 else
4922 tv_eternity(&t->swexpire);
4923 }
4924 }
4925 return 0;
4926 }
4927 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004928 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004929 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004930 tv_eternity(&t->srexpire);
4931 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004932 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004933 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004934 if (!(t->flags & SN_ERR_MASK))
4935 t->flags |= SN_ERR_SRVCL;
4936 if (!(t->flags & SN_FINST_MASK))
4937 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004938 return 1;
4939 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004940 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4941 //FD_CLR(t->srv_fd, StaticReadEvent);
4942 tv_eternity(&t->srexpire);
4943 fd_delete(t->srv_fd);
4944 //close(t->srv_fd);
4945 t->srv_state = SV_STCLOSE;
4946 return 1;
4947 }
4948 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4949 //FD_CLR(t->srv_fd, StaticReadEvent);
4950 tv_eternity(&t->srexpire);
4951 fd_delete(t->srv_fd);
4952 //close(t->srv_fd);
4953 t->srv_state = SV_STCLOSE;
4954 if (!(t->flags & SN_ERR_MASK))
4955 t->flags |= SN_ERR_SRVTO;
4956 if (!(t->flags & SN_FINST_MASK))
4957 t->flags |= SN_FINST_D;
4958 return 1;
4959 }
willy tarreau0f7af912005-12-17 12:21:26 +01004960 else if (rep->l == BUFSIZE) { /* no room to read more data */
4961 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4962 FD_CLR(t->srv_fd, StaticReadEvent);
4963 tv_eternity(&t->srexpire);
4964 }
4965 }
4966 else {
4967 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4968 FD_SET(t->srv_fd, StaticReadEvent);
4969 if (t->proxy->srvtimeout)
4970 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4971 else
4972 tv_eternity(&t->srexpire);
4973 }
4974 }
4975 return 0;
4976 }
4977 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004978 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004979 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004980 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 +01004981 write(1, trash, len);
4982 }
4983 return 0;
4984 }
4985 return 0;
4986}
4987
4988
willy tarreau5cbea6f2005-12-17 12:48:26 +01004989/* Processes the client and server jobs of a session task, then
4990 * puts it back to the wait queue in a clean state, or
4991 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01004992 * the time the task accepts to wait, or TIME_ETERNITY for
4993 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01004994 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004995int process_session(struct task *t) {
4996 struct session *s = t->context;
4997 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004998
willy tarreau5cbea6f2005-12-17 12:48:26 +01004999 do {
5000 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005001 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005002 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005003 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005004 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005005 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005006 } while (fsm_resync);
5007
5008 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005009 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005010 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005011
willy tarreau5cbea6f2005-12-17 12:48:26 +01005012 tv_min(&min1, &s->crexpire, &s->cwexpire);
5013 tv_min(&min2, &s->srexpire, &s->swexpire);
5014 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005015 tv_min(&t->expire, &min1, &min2);
5016
5017 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005018 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005019
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005020#ifdef DEBUG_FULL
5021 /* DEBUG code : this should never ever happen, otherwise it indicates
5022 * that a task still has something to do and will provoke a quick loop.
5023 */
5024 if (tv_remain2(&now, &t->expire) <= 0)
5025 exit(100);
5026#endif
5027
willy tarreaub952e1d2005-12-18 01:31:20 +01005028 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005029 }
5030
willy tarreau5cbea6f2005-12-17 12:48:26 +01005031 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005032 actconn--;
5033
willy tarreau982249e2005-12-18 00:57:06 +01005034 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005035 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005036 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 +01005037 write(1, trash, len);
5038 }
5039
willy tarreau750a4722005-12-17 13:21:24 +01005040 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005041 if (s->rep != NULL)
5042 s->logs.bytes = s->rep->total;
5043
willy tarreau9fe663a2005-12-17 13:02:59 +01005044 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005045 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005046 sess_log(s);
5047
willy tarreau0f7af912005-12-17 12:21:26 +01005048 /* the task MUST not be in the run queue anymore */
5049 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005050 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005051 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005052 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005053}
5054
5055
5056
5057/*
5058 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005059 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005060 */
5061int process_chk(struct task *t) {
5062 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005063 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005064 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005065
willy tarreauef900ab2005-12-17 12:52:52 +01005066 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005067
willy tarreau25424f82006-03-19 19:37:48 +01005068 new_chk:
5069 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005070 if (fd < 0) { /* no check currently running */
5071 //fprintf(stderr, "process_chk: 2\n");
5072 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5073 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005074 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005075 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005076
5077 /* we don't send any health-checks when the proxy is stopped or when
5078 * the server should not be checked.
5079 */
5080 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005081 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5082 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005083 task_queue(t); /* restore t to its place in the task list */
5084 return tv_remain2(&now, &t->expire);
5085 }
5086
willy tarreau5cbea6f2005-12-17 12:48:26 +01005087 /* we'll initiate a new check */
5088 s->result = 0; /* no result yet */
5089 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005090 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005091 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5092 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5093 //fprintf(stderr, "process_chk: 3\n");
5094
willy tarreaua41a8b42005-12-17 14:02:24 +01005095 /* we'll connect to the check port on the server */
5096 sa = s->addr;
5097 sa.sin_port = htons(s->check_port);
5098
willy tarreau0174f312005-12-18 01:02:42 +01005099 /* allow specific binding :
5100 * - server-specific at first
5101 * - proxy-specific next
5102 */
5103 if (s->state & SRV_BIND_SRC) {
5104 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5105 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5106 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5107 s->proxy->id, s->id);
5108 s->result = -1;
5109 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005110 }
willy tarreau0174f312005-12-18 01:02:42 +01005111 else if (s->proxy->options & PR_O_BIND_SRC) {
5112 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5113 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5114 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5115 s->proxy->id);
5116 s->result = -1;
5117 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005118 }
willy tarreau0174f312005-12-18 01:02:42 +01005119
5120 if (!s->result) {
5121 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5122 /* OK, connection in progress or established */
5123
5124 //fprintf(stderr, "process_chk: 4\n");
5125
5126 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5127 fdtab[fd].owner = t;
5128 fdtab[fd].read = &event_srv_chk_r;
5129 fdtab[fd].write = &event_srv_chk_w;
5130 fdtab[fd].state = FD_STCONN; /* connection in progress */
5131 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005132#ifdef DEBUG_FULL
5133 assert (!FD_ISSET(fd, StaticReadEvent));
5134#endif
willy tarreau0174f312005-12-18 01:02:42 +01005135 fd_insert(fd);
5136 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5137 tv_delayfrom(&t->expire, &now, s->inter);
5138 task_queue(t); /* restore t to its place in the task list */
5139 return tv_remain(&now, &t->expire);
5140 }
5141 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5142 s->result = -1; /* a real error */
5143 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005144 }
5145 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005146 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005147 }
5148
5149 if (!s->result) { /* nothing done */
5150 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005151 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5152 tv_delayfrom(&t->expire, &t->expire, s->inter);
5153 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005154 }
5155
5156 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005157 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005158 s->health--; /* still good */
5159 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005160 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005161 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005162 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005163 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01005164
willy tarreaudd07e972005-12-18 00:48:48 +01005165 if (find_server(s->proxy) == NULL) {
5166 Alert("Proxy %s has no server available !\n", s->proxy->id);
5167 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5168 }
5169 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005170 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005171 }
5172
5173 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005174 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005175 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5176 tv_delayfrom(&t->expire, &t->expire, s->inter);
5177 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005178 }
5179 else {
5180 //fprintf(stderr, "process_chk: 8\n");
5181 /* there was a test running */
5182 if (s->result > 0) { /* good server detected */
5183 //fprintf(stderr, "process_chk: 9\n");
5184 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005185 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005186 if (s->health == s->rise) {
willy tarreaufd6dfe72006-03-19 19:38:19 +01005187 Warning("Server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005188 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005189 }
willy tarreauef900ab2005-12-17 12:52:52 +01005190
willy tarreaue47c8d72005-12-17 12:55:52 +01005191 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005192 s->state |= SRV_RUNNING;
5193 }
willy tarreauef900ab2005-12-17 12:52:52 +01005194 s->curfd = -1; /* no check running anymore */
5195 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005196 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005197 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5198 tv_delayfrom(&t->expire, &t->expire, s->inter);
5199 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005200 }
5201 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5202 //fprintf(stderr, "process_chk: 10\n");
5203 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005204 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005205 s->health--; /* still good */
5206 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005207 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005208
willy tarreaudd07e972005-12-18 00:48:48 +01005209 if (s->health == s->rise) {
5210 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005211 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01005212
5213 if (find_server(s->proxy) == NULL) {
5214 Alert("Proxy %s has no server available !\n", s->proxy->id);
5215 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5216 }
willy tarreau535ae7a2005-12-17 12:58:00 +01005217 }
willy tarreauef900ab2005-12-17 12:52:52 +01005218
willy tarreau5cbea6f2005-12-17 12:48:26 +01005219 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005220 }
5221 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005222 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005223 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005224 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5225 tv_delayfrom(&t->expire, &t->expire, s->inter);
5226 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005227 }
5228 /* if result is 0 and there's no timeout, we have to wait again */
5229 }
5230 //fprintf(stderr, "process_chk: 11\n");
5231 s->result = 0;
5232 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005233 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005234}
5235
5236
willy tarreau5cbea6f2005-12-17 12:48:26 +01005237
willy tarreau0f7af912005-12-17 12:21:26 +01005238#if STATTIME > 0
5239int stats(void);
5240#endif
5241
5242/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005243 * This does 4 things :
5244 * - wake up all expired tasks
5245 * - call all runnable tasks
5246 * - call maintain_proxies() to enable/disable the listeners
5247 * - return the delay till next event in ms, -1 = wait indefinitely
5248 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5249 *
willy tarreau0f7af912005-12-17 12:21:26 +01005250 */
5251
willy tarreau1c2ad212005-12-18 01:11:29 +01005252int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005253 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005254 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005255 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005256
willy tarreaub952e1d2005-12-18 01:31:20 +01005257 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005258
willy tarreau1c2ad212005-12-18 01:11:29 +01005259 /* look for expired tasks and add them to the run queue.
5260 */
5261 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5262 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5263 tnext = t->next;
5264 if (t->state & TASK_RUNNING)
5265 continue;
5266
willy tarreaub952e1d2005-12-18 01:31:20 +01005267 if (tv_iseternity(&t->expire))
5268 continue;
5269
willy tarreau1c2ad212005-12-18 01:11:29 +01005270 /* wakeup expired entries. It doesn't matter if they are
5271 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005272 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005273 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005274 task_wakeup(&rq, t);
5275 }
5276 else {
5277 /* first non-runnable task. Use its expiration date as an upper bound */
5278 int temp_time = tv_remain(&now, &t->expire);
5279 if (temp_time)
5280 next_time = temp_time;
5281 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005282 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005283 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005284
willy tarreau1c2ad212005-12-18 01:11:29 +01005285 /* process each task in the run queue now. Each task may be deleted
5286 * since we only use tnext.
5287 */
5288 tnext = rq;
5289 while ((t = tnext) != NULL) {
5290 int temp_time;
5291
5292 tnext = t->rqnext;
5293 task_sleep(&rq, t);
5294 temp_time = t->process(t);
5295 next_time = MINTIME(temp_time, next_time);
5296 }
5297
5298 /* maintain all proxies in a consistent state. This should quickly become a task */
5299 time2 = maintain_proxies();
5300 return MINTIME(time2, next_time);
5301}
5302
5303
5304#if defined(ENABLE_EPOLL)
5305
5306/*
5307 * Main epoll() loop.
5308 */
5309
5310/* does 3 actions :
5311 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5312 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5313 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5314 *
5315 * returns 0 if initialization failed, !0 otherwise.
5316 */
5317
5318int epoll_loop(int action) {
5319 int next_time;
5320 int status;
5321 int fd;
5322
5323 int fds, count;
5324 int pr, pw, sr, sw;
5325 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5326 struct epoll_event ev;
5327
5328 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005329 static struct epoll_event *epoll_events = NULL;
5330 static int epoll_fd;
5331
5332 if (action == POLL_LOOP_ACTION_INIT) {
5333 epoll_fd = epoll_create(global.maxsock + 1);
5334 if (epoll_fd < 0)
5335 return 0;
5336 else {
5337 epoll_events = (struct epoll_event*)
5338 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5339 PrevReadEvent = (fd_set *)
5340 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5341 PrevWriteEvent = (fd_set *)
5342 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005343 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005344 return 1;
5345 }
5346 else if (action == POLL_LOOP_ACTION_CLEAN) {
5347 if (PrevWriteEvent) free(PrevWriteEvent);
5348 if (PrevReadEvent) free(PrevReadEvent);
5349 if (epoll_events) free(epoll_events);
5350 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005351 epoll_fd = 0;
5352 return 1;
5353 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005354
willy tarreau1c2ad212005-12-18 01:11:29 +01005355 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005356
willy tarreau1c2ad212005-12-18 01:11:29 +01005357 tv_now(&now);
5358
5359 while (1) {
5360 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005361
5362 /* stop when there's no connection left and we don't allow them anymore */
5363 if (!actconn && listeners == 0)
5364 break;
5365
willy tarreau0f7af912005-12-17 12:21:26 +01005366#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005367 {
5368 int time2;
5369 time2 = stats();
5370 next_time = MINTIME(time2, next_time);
5371 }
willy tarreau0f7af912005-12-17 12:21:26 +01005372#endif
5373
willy tarreau1c2ad212005-12-18 01:11:29 +01005374 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5375
5376 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5377 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5378
5379 if ((ro^rn) | (wo^wn)) {
5380 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5381#define FDSETS_ARE_INT_ALIGNED
5382#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005383
willy tarreauad90a0c2005-12-18 01:09:15 +01005384#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5385#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005386 pr = (ro >> count) & 1;
5387 pw = (wo >> count) & 1;
5388 sr = (rn >> count) & 1;
5389 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005390#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005391 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5392 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5393 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5394 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005395#endif
5396#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005397 pr = FD_ISSET(fd, PrevReadEvent);
5398 pw = FD_ISSET(fd, PrevWriteEvent);
5399 sr = FD_ISSET(fd, StaticReadEvent);
5400 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005401#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005402 if (!((sr^pr) | (sw^pw)))
5403 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005404
willy tarreau1c2ad212005-12-18 01:11:29 +01005405 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5406 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005407
willy tarreaub952e1d2005-12-18 01:31:20 +01005408#ifdef EPOLL_CTL_MOD_WORKAROUND
5409 /* I encountered a rarely reproducible problem with
5410 * EPOLL_CTL_MOD where a modified FD (systematically
5411 * the one in epoll_events[0], fd#7) would sometimes
5412 * be set EPOLL_OUT while asked for a read ! This is
5413 * with the 2.4 epoll patch. The workaround is to
5414 * delete then recreate in case of modification.
5415 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5416 * nor RHEL kernels.
5417 */
5418
5419 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5420 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5421
5422 if ((sr | sw))
5423 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5424#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005425 if ((pr | pw)) {
5426 /* the file-descriptor already exists... */
5427 if ((sr | sw)) {
5428 /* ...and it will still exist */
5429 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5430 // perror("epoll_ctl(MOD)");
5431 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005432 }
5433 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005434 /* ...and it will be removed */
5435 if (fdtab[fd].state != FD_STCLOSE &&
5436 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5437 // perror("epoll_ctl(DEL)");
5438 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005439 }
5440 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005441 } else {
5442 /* the file-descriptor did not exist, let's add it */
5443 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5444 // perror("epoll_ctl(ADD)");
5445 // exit(1);
5446 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005447 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005448#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005449 }
5450 ((int*)PrevReadEvent)[fds] = rn;
5451 ((int*)PrevWriteEvent)[fds] = wn;
5452 }
5453 }
5454
5455 /* now let's wait for events */
5456 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5457 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005458
willy tarreau1c2ad212005-12-18 01:11:29 +01005459 for (count = 0; count < status; count++) {
5460 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01005461
5462 if (FD_ISSET(fd, StaticReadEvent)) {
5463 if (fdtab[fd].state == FD_STCLOSE)
5464 continue;
5465 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5466 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005467 }
willy tarreau05be12b2006-03-19 19:35:00 +01005468
5469 if (FD_ISSET(fd, StaticWriteEvent)) {
5470 if (fdtab[fd].state == FD_STCLOSE)
5471 continue;
5472 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5473 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005474 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005475 }
5476 }
5477 return 1;
5478}
5479#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005480
willy tarreauad90a0c2005-12-18 01:09:15 +01005481
willy tarreau5cbea6f2005-12-17 12:48:26 +01005482
willy tarreau1c2ad212005-12-18 01:11:29 +01005483#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005484
willy tarreau1c2ad212005-12-18 01:11:29 +01005485/*
5486 * Main poll() loop.
5487 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005488
willy tarreau1c2ad212005-12-18 01:11:29 +01005489/* does 3 actions :
5490 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5491 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5492 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5493 *
5494 * returns 0 if initialization failed, !0 otherwise.
5495 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005496
willy tarreau1c2ad212005-12-18 01:11:29 +01005497int poll_loop(int action) {
5498 int next_time;
5499 int status;
5500 int fd, nbfd;
5501
5502 int fds, count;
5503 int sr, sw;
5504 unsigned rn, wn; /* read new, write new */
5505
5506 /* private data */
5507 static struct pollfd *poll_events = NULL;
5508
5509 if (action == POLL_LOOP_ACTION_INIT) {
5510 poll_events = (struct pollfd*)
5511 calloc(1, sizeof(struct pollfd) * global.maxsock);
5512 return 1;
5513 }
5514 else if (action == POLL_LOOP_ACTION_CLEAN) {
5515 if (poll_events)
5516 free(poll_events);
5517 return 1;
5518 }
5519
5520 /* OK, it's POLL_LOOP_ACTION_RUN */
5521
5522 tv_now(&now);
5523
5524 while (1) {
5525 next_time = process_runnable_tasks();
5526
5527 /* stop when there's no connection left and we don't allow them anymore */
5528 if (!actconn && listeners == 0)
5529 break;
5530
5531#if STATTIME > 0
5532 {
5533 int time2;
5534 time2 = stats();
5535 next_time = MINTIME(time2, next_time);
5536 }
5537#endif
5538
5539
5540 nbfd = 0;
5541 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5542
5543 rn = ((int*)StaticReadEvent)[fds];
5544 wn = ((int*)StaticWriteEvent)[fds];
5545
5546 if ((rn|wn)) {
5547 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5548#define FDSETS_ARE_INT_ALIGNED
5549#ifdef FDSETS_ARE_INT_ALIGNED
5550
5551#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5552#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5553 sr = (rn >> count) & 1;
5554 sw = (wn >> count) & 1;
5555#else
5556 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5557 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5558#endif
5559#else
5560 sr = FD_ISSET(fd, StaticReadEvent);
5561 sw = FD_ISSET(fd, StaticWriteEvent);
5562#endif
5563 if ((sr|sw)) {
5564 poll_events[nbfd].fd = fd;
5565 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5566 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005567 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005568 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005569 }
5570 }
5571
5572 /* now let's wait for events */
5573 status = poll(poll_events, nbfd, next_time);
5574 tv_now(&now);
5575
5576 for (count = 0; status > 0 && count < nbfd; count++) {
5577 fd = poll_events[count].fd;
5578
5579 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5580 continue;
5581
5582 /* ok, we found one active fd */
5583 status--;
5584
willy tarreau05be12b2006-03-19 19:35:00 +01005585 if (FD_ISSET(fd, StaticReadEvent)) {
5586 if (fdtab[fd].state == FD_STCLOSE)
5587 continue;
5588 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5589 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005590 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005591
willy tarreau05be12b2006-03-19 19:35:00 +01005592 if (FD_ISSET(fd, StaticWriteEvent)) {
5593 if (fdtab[fd].state == FD_STCLOSE)
5594 continue;
5595 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5596 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005597 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005598 }
5599 }
5600 return 1;
5601}
willy tarreauad90a0c2005-12-18 01:09:15 +01005602#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005603
willy tarreauad90a0c2005-12-18 01:09:15 +01005604
willy tarreauad90a0c2005-12-18 01:09:15 +01005605
willy tarreau1c2ad212005-12-18 01:11:29 +01005606/*
5607 * Main select() loop.
5608 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005609
willy tarreau1c2ad212005-12-18 01:11:29 +01005610/* does 3 actions :
5611 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5612 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5613 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5614 *
5615 * returns 0 if initialization failed, !0 otherwise.
5616 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005617
willy tarreauad90a0c2005-12-18 01:09:15 +01005618
willy tarreau1c2ad212005-12-18 01:11:29 +01005619int select_loop(int action) {
5620 int next_time;
5621 int status;
5622 int fd,i;
5623 struct timeval delta;
5624 int readnotnull, writenotnull;
5625 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005626
willy tarreau1c2ad212005-12-18 01:11:29 +01005627 if (action == POLL_LOOP_ACTION_INIT) {
5628 ReadEvent = (fd_set *)
5629 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5630 WriteEvent = (fd_set *)
5631 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5632 return 1;
5633 }
5634 else if (action == POLL_LOOP_ACTION_CLEAN) {
5635 if (WriteEvent) free(WriteEvent);
5636 if (ReadEvent) free(ReadEvent);
5637 return 1;
5638 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005639
willy tarreau1c2ad212005-12-18 01:11:29 +01005640 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005641
willy tarreau1c2ad212005-12-18 01:11:29 +01005642 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005643
willy tarreau1c2ad212005-12-18 01:11:29 +01005644 while (1) {
5645 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005646
willy tarreau1c2ad212005-12-18 01:11:29 +01005647 /* stop when there's no connection left and we don't allow them anymore */
5648 if (!actconn && listeners == 0)
5649 break;
5650
5651#if STATTIME > 0
5652 {
5653 int time2;
5654 time2 = stats();
5655 next_time = MINTIME(time2, next_time);
5656 }
5657#endif
5658
willy tarreau1c2ad212005-12-18 01:11:29 +01005659 if (next_time > 0) { /* FIXME */
5660 /* Convert to timeval */
5661 /* to avoid eventual select loops due to timer precision */
5662 next_time += SCHEDULER_RESOLUTION;
5663 delta.tv_sec = next_time / 1000;
5664 delta.tv_usec = (next_time % 1000) * 1000;
5665 }
5666 else if (next_time == 0) { /* allow select to return immediately when needed */
5667 delta.tv_sec = delta.tv_usec = 0;
5668 }
5669
5670
5671 /* let's restore fdset state */
5672
5673 readnotnull = 0; writenotnull = 0;
5674 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5675 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5676 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5677 }
5678
5679 // /* just a verification code, needs to be removed for performance */
5680 // for (i=0; i<maxfd; i++) {
5681 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5682 // abort();
5683 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5684 // abort();
5685 //
5686 // }
5687
5688 status = select(maxfd,
5689 readnotnull ? ReadEvent : NULL,
5690 writenotnull ? WriteEvent : NULL,
5691 NULL,
5692 (next_time >= 0) ? &delta : NULL);
5693
5694 /* this is an experiment on the separation of the select work */
5695 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5696 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5697
5698 tv_now(&now);
5699
5700 if (status > 0) { /* must proceed with events */
5701
5702 int fds;
5703 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005704
willy tarreau1c2ad212005-12-18 01:11:29 +01005705 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5706 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5707 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5708
5709 /* if we specify read first, the accepts and zero reads will be
5710 * seen first. Moreover, system buffers will be flushed faster.
5711 */
willy tarreau05be12b2006-03-19 19:35:00 +01005712 if (FD_ISSET(fd, ReadEvent)) {
5713 if (fdtab[fd].state == FD_STCLOSE)
5714 continue;
5715 fdtab[fd].read(fd);
5716 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005717
willy tarreau05be12b2006-03-19 19:35:00 +01005718 if (FD_ISSET(fd, WriteEvent)) {
5719 if (fdtab[fd].state == FD_STCLOSE)
5720 continue;
5721 fdtab[fd].write(fd);
5722 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005723 }
5724 }
5725 else {
5726 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005727 }
willy tarreau0f7af912005-12-17 12:21:26 +01005728 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005729 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005730}
5731
5732
5733#if STATTIME > 0
5734/*
5735 * Display proxy statistics regularly. It is designed to be called from the
5736 * select_loop().
5737 */
5738int stats(void) {
5739 static int lines;
5740 static struct timeval nextevt;
5741 static struct timeval lastevt;
5742 static struct timeval starttime = {0,0};
5743 unsigned long totaltime, deltatime;
5744 int ret;
5745
willy tarreau750a4722005-12-17 13:21:24 +01005746 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005747 deltatime = (tv_diff(&lastevt, &now)?:1);
5748 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005749
willy tarreau9fe663a2005-12-17 13:02:59 +01005750 if (global.mode & MODE_STATS) {
5751 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005752 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005753 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5754 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005755 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005756 actconn, totalconn,
5757 stats_tsk_new, stats_tsk_good,
5758 stats_tsk_left, stats_tsk_right,
5759 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5760 }
5761 }
5762
5763 tv_delayfrom(&nextevt, &now, STATTIME);
5764
5765 lastevt=now;
5766 }
5767 ret = tv_remain(&now, &nextevt);
5768 return ret;
5769}
5770#endif
5771
5772
5773/*
5774 * this function enables proxies when there are enough free sessions,
5775 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005776 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005777 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005778 */
5779static int maintain_proxies(void) {
5780 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005781 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005782 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005783
5784 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005785 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005786
5787 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005788 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005789 while (p) {
5790 if (p->nbconn < p->maxconn) {
5791 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005792 for (l = p->listen; l != NULL; l = l->next) {
5793 FD_SET(l->fd, StaticReadEvent);
5794 }
willy tarreau0f7af912005-12-17 12:21:26 +01005795 p->state = PR_STRUN;
5796 }
5797 }
5798 else {
5799 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005800 for (l = p->listen; l != NULL; l = l->next) {
5801 FD_CLR(l->fd, StaticReadEvent);
5802 }
willy tarreau0f7af912005-12-17 12:21:26 +01005803 p->state = PR_STIDLE;
5804 }
5805 }
5806 p = p->next;
5807 }
5808 }
5809 else { /* block all proxies */
5810 while (p) {
5811 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005812 for (l = p->listen; l != NULL; l = l->next) {
5813 FD_CLR(l->fd, StaticReadEvent);
5814 }
willy tarreau0f7af912005-12-17 12:21:26 +01005815 p->state = PR_STIDLE;
5816 }
5817 p = p->next;
5818 }
5819 }
5820
willy tarreau5cbea6f2005-12-17 12:48:26 +01005821 if (stopping) {
5822 p = proxy;
5823 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01005824 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005825 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01005826 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005827 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005828 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005829 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005830
willy tarreaua41a8b42005-12-17 14:02:24 +01005831 for (l = p->listen; l != NULL; l = l->next) {
5832 fd_delete(l->fd);
5833 listeners--;
5834 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01005835 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005836 }
5837 else {
5838 tleft = MINTIME(t, tleft);
5839 }
5840 }
5841 p = p->next;
5842 }
5843 }
5844 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01005845}
5846
5847/*
5848 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01005849 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
5850 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01005851 */
5852static void soft_stop(void) {
5853 struct proxy *p;
5854
5855 stopping = 1;
5856 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005857 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01005858 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01005859 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005860 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01005861 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01005862 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01005863 }
willy tarreau0f7af912005-12-17 12:21:26 +01005864 p = p->next;
5865 }
5866}
5867
willy tarreaudbd3bef2006-01-20 19:35:18 +01005868static void pause_proxy(struct proxy *p) {
5869 struct listener *l;
5870 for (l = p->listen; l != NULL; l = l->next) {
5871 shutdown(l->fd, SHUT_RD);
5872 FD_CLR(l->fd, StaticReadEvent);
5873 p->state = PR_STPAUSED;
5874 }
5875}
5876
5877/*
5878 * This function temporarily disables listening so that another new instance
5879 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01005880 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01005881 * the proxy, or a SIGTTIN can be sent to listen again.
5882 */
5883static void pause_proxies(void) {
5884 struct proxy *p;
5885
5886 p = proxy;
5887 tv_now(&now); /* else, the old time before select will be used */
5888 while (p) {
5889 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
5890 Warning("Pausing proxy %s.\n", p->id);
5891 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
5892 pause_proxy(p);
5893 }
5894 p = p->next;
5895 }
5896}
5897
5898
5899/*
5900 * This function reactivates listening. This can be used after a call to
5901 * sig_pause(), for example when a new instance has failed starting up.
5902 * It is designed to be called upon reception of a SIGTTIN.
5903 */
5904static void listen_proxies(void) {
5905 struct proxy *p;
5906 struct listener *l;
5907
5908 p = proxy;
5909 tv_now(&now); /* else, the old time before select will be used */
5910 while (p) {
5911 if (p->state == PR_STPAUSED) {
5912 Warning("Enabling proxy %s.\n", p->id);
5913 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
5914
5915 for (l = p->listen; l != NULL; l = l->next) {
5916 if (listen(l->fd, p->maxconn) == 0) {
5917 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
5918 FD_SET(l->fd, StaticReadEvent);
5919 p->state = PR_STRUN;
5920 }
5921 else
5922 p->state = PR_STIDLE;
5923 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01005924 int port;
5925
5926 if (l->addr.ss_family == AF_INET6)
5927 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
5928 else
5929 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
5930
willy tarreaudbd3bef2006-01-20 19:35:18 +01005931 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01005932 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01005933 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01005934 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01005935 /* Another port might have been enabled. Let's stop everything. */
5936 pause_proxy(p);
5937 break;
5938 }
5939 }
5940 }
5941 p = p->next;
5942 }
5943}
5944
5945
willy tarreau0f7af912005-12-17 12:21:26 +01005946/*
5947 * upon SIGUSR1, let's have a soft stop.
5948 */
5949void sig_soft_stop(int sig) {
5950 soft_stop();
5951 signal(sig, SIG_IGN);
5952}
5953
willy tarreaudbd3bef2006-01-20 19:35:18 +01005954/*
5955 * upon SIGTTOU, we pause everything
5956 */
5957void sig_pause(int sig) {
5958 pause_proxies();
5959 signal(sig, sig_pause);
5960}
willy tarreau0f7af912005-12-17 12:21:26 +01005961
willy tarreau8337c6b2005-12-17 13:41:01 +01005962/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01005963 * upon SIGTTIN, let's have a soft stop.
5964 */
5965void sig_listen(int sig) {
5966 listen_proxies();
5967 signal(sig, sig_listen);
5968}
5969
5970/*
willy tarreau8337c6b2005-12-17 13:41:01 +01005971 * this function dumps every server's state when the process receives SIGHUP.
5972 */
5973void sig_dump_state(int sig) {
5974 struct proxy *p = proxy;
5975
5976 Warning("SIGHUP received, dumping servers states.\n");
5977 while (p) {
5978 struct server *s = p->srv;
5979
5980 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
5981 while (s) {
5982 if (s->state & SRV_RUNNING) {
willy tarreaufd6dfe72006-03-19 19:38:19 +01005983 Warning("SIGHUP: Server %s/%s is UP.\n", p->id, s->id);
5984 send_log(p, LOG_NOTICE, "SIGUP: Server %s/%s is UP.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01005985 }
5986 else {
willy tarreaufd6dfe72006-03-19 19:38:19 +01005987 Warning("SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
5988 send_log(p, LOG_NOTICE, "SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01005989 }
5990 s = s->next;
5991 }
willy tarreaudd07e972005-12-18 00:48:48 +01005992
5993 if (find_server(p) == NULL) {
willy tarreaufd6dfe72006-03-19 19:38:19 +01005994 Warning("SIGHUP: Proxy %s has no server available !\n", p);
5995 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s has no server available !\n", p);
willy tarreaudd07e972005-12-18 00:48:48 +01005996 }
5997
willy tarreau8337c6b2005-12-17 13:41:01 +01005998 p = p->next;
5999 }
6000 signal(sig, sig_dump_state);
6001}
6002
willy tarreau0f7af912005-12-17 12:21:26 +01006003void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006004 struct task *t, *tnext;
6005 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006006
willy tarreau5cbea6f2005-12-17 12:48:26 +01006007 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
6008 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
6009 tnext = t->next;
6010 s = t->context;
6011 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6012 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6013 "req=%d, rep=%d, clifd=%d\n",
6014 s, tv_remain(&now, &t->expire),
6015 s->cli_state,
6016 s->srv_state,
6017 FD_ISSET(s->cli_fd, StaticReadEvent),
6018 FD_ISSET(s->cli_fd, StaticWriteEvent),
6019 FD_ISSET(s->srv_fd, StaticReadEvent),
6020 FD_ISSET(s->srv_fd, StaticWriteEvent),
6021 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6022 );
willy tarreau0f7af912005-12-17 12:21:26 +01006023 }
willy tarreau12350152005-12-18 01:03:27 +01006024}
6025
willy tarreau64a3cc32005-12-18 01:13:11 +01006026#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006027static void fast_stop(void)
6028{
6029 struct proxy *p;
6030 p = proxy;
6031 while (p) {
6032 p->grace = 0;
6033 p = p->next;
6034 }
6035 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006036}
6037
willy tarreau12350152005-12-18 01:03:27 +01006038void sig_int(int sig) {
6039 /* This would normally be a hard stop,
6040 but we want to be sure about deallocation,
6041 and so on, so we do a soft stop with
6042 0 GRACE time
6043 */
6044 fast_stop();
6045 /* If we are killed twice, we decide to die*/
6046 signal(sig, SIG_DFL);
6047}
6048
6049void sig_term(int sig) {
6050 /* This would normally be a hard stop,
6051 but we want to be sure about deallocation,
6052 and so on, so we do a soft stop with
6053 0 GRACE time
6054 */
6055 fast_stop();
6056 /* If we are killed twice, we decide to die*/
6057 signal(sig, SIG_DFL);
6058}
willy tarreau64a3cc32005-12-18 01:13:11 +01006059#endif
willy tarreau12350152005-12-18 01:03:27 +01006060
willy tarreauc1f47532005-12-18 01:08:26 +01006061/* returns the pointer to an error in the replacement string, or NULL if OK */
6062char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006063 struct hdr_exp *exp;
6064
willy tarreauc1f47532005-12-18 01:08:26 +01006065 if (replace != NULL) {
6066 char *err;
6067 err = check_replace_string(replace);
6068 if (err)
6069 return err;
6070 }
6071
willy tarreaue39cd132005-12-17 13:00:18 +01006072 while (*head != NULL)
6073 head = &(*head)->next;
6074
6075 exp = calloc(1, sizeof(struct hdr_exp));
6076
6077 exp->preg = preg;
6078 exp->replace = replace;
6079 exp->action = action;
6080 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006081
6082 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006083}
6084
willy tarreau9fe663a2005-12-17 13:02:59 +01006085
willy tarreau0f7af912005-12-17 12:21:26 +01006086/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006087 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006088 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006089int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006090
willy tarreau9fe663a2005-12-17 13:02:59 +01006091 if (!strcmp(args[0], "global")) { /* new section */
6092 /* no option, nothing special to do */
6093 return 0;
6094 }
6095 else if (!strcmp(args[0], "daemon")) {
6096 global.mode |= MODE_DAEMON;
6097 }
6098 else if (!strcmp(args[0], "debug")) {
6099 global.mode |= MODE_DEBUG;
6100 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006101 else if (!strcmp(args[0], "noepoll")) {
6102 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6103 }
6104 else if (!strcmp(args[0], "nopoll")) {
6105 cfg_polling_mechanism &= ~POLL_USE_POLL;
6106 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006107 else if (!strcmp(args[0], "quiet")) {
6108 global.mode |= MODE_QUIET;
6109 }
6110 else if (!strcmp(args[0], "stats")) {
6111 global.mode |= MODE_STATS;
6112 }
6113 else if (!strcmp(args[0], "uid")) {
6114 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006115 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006116 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006117 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006118 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006119 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006120 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006121 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006122 global.uid = atol(args[1]);
6123 }
6124 else if (!strcmp(args[0], "gid")) {
6125 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006126 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006127 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006128 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006129 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006130 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006131 return -1;
6132 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006133 global.gid = atol(args[1]);
6134 }
6135 else if (!strcmp(args[0], "nbproc")) {
6136 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006137 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006138 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006139 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006140 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006141 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006142 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006143 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006144 global.nbproc = atol(args[1]);
6145 }
6146 else if (!strcmp(args[0], "maxconn")) {
6147 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006148 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006149 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006150 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006151 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006152 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006153 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006154 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006155 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006156#ifdef SYSTEM_MAXCONN
6157 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6158 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);
6159 global.maxconn = DEFAULT_MAXCONN;
6160 }
6161#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006162 }
willy tarreaub1285d52005-12-18 01:20:14 +01006163 else if (!strcmp(args[0], "ulimit-n")) {
6164 if (global.rlimit_nofile != 0) {
6165 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6166 return 0;
6167 }
6168 if (*(args[1]) == 0) {
6169 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6170 return -1;
6171 }
6172 global.rlimit_nofile = atol(args[1]);
6173 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006174 else if (!strcmp(args[0], "chroot")) {
6175 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006176 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006177 return 0;
6178 }
6179 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006180 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006181 return -1;
6182 }
6183 global.chroot = strdup(args[1]);
6184 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006185 else if (!strcmp(args[0], "pidfile")) {
6186 if (global.pidfile != NULL) {
6187 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6188 return 0;
6189 }
6190 if (*(args[1]) == 0) {
6191 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6192 return -1;
6193 }
6194 global.pidfile = strdup(args[1]);
6195 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006196 else if (!strcmp(args[0], "log")) { /* syslog server address */
6197 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006198 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006199
6200 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006201 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006202 return -1;
6203 }
6204
6205 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6206 if (!strcmp(log_facilities[facility], args[2]))
6207 break;
6208
6209 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006210 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006211 exit(1);
6212 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006213
6214 level = 7; /* max syslog level = debug */
6215 if (*(args[3])) {
6216 while (level >= 0 && strcmp(log_levels[level], args[3]))
6217 level--;
6218 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006219 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006220 exit(1);
6221 }
6222 }
6223
willy tarreau9fe663a2005-12-17 13:02:59 +01006224 sa = str2sa(args[1]);
6225 if (!sa->sin_port)
6226 sa->sin_port = htons(SYSLOG_PORT);
6227
6228 if (global.logfac1 == -1) {
6229 global.logsrv1 = *sa;
6230 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006231 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006232 }
6233 else if (global.logfac2 == -1) {
6234 global.logsrv2 = *sa;
6235 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006236 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006237 }
6238 else {
6239 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6240 return -1;
6241 }
6242
6243 }
6244 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006245 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006246 return -1;
6247 }
6248 return 0;
6249}
6250
6251
willy tarreaua41a8b42005-12-17 14:02:24 +01006252void init_default_instance() {
6253 memset(&defproxy, 0, sizeof(defproxy));
6254 defproxy.mode = PR_MODE_TCP;
6255 defproxy.state = PR_STNEW;
6256 defproxy.maxconn = cfg_maxpconn;
6257 defproxy.conn_retries = CONN_RETRIES;
6258 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6259}
6260
willy tarreau9fe663a2005-12-17 13:02:59 +01006261/*
6262 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6263 */
6264int cfg_parse_listen(char *file, int linenum, char **args) {
6265 static struct proxy *curproxy = NULL;
6266 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006267 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006268 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006269
6270 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006271 if (!*args[1]) {
6272 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6273 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006274 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006275 return -1;
6276 }
6277
6278 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006279 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006280 return -1;
6281 }
6282 curproxy->next = proxy;
6283 proxy = curproxy;
6284 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006285
6286 /* parse the listener address if any */
6287 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006288 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006289 if (!curproxy->listen)
6290 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006291 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01006292 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006293
willy tarreau9fe663a2005-12-17 13:02:59 +01006294 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006295 curproxy->state = defproxy.state;
6296 curproxy->maxconn = defproxy.maxconn;
6297 curproxy->conn_retries = defproxy.conn_retries;
6298 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006299
6300 if (defproxy.check_req)
6301 curproxy->check_req = strdup(defproxy.check_req);
6302 curproxy->check_len = defproxy.check_len;
6303
6304 if (defproxy.cookie_name)
6305 curproxy->cookie_name = strdup(defproxy.cookie_name);
6306 curproxy->cookie_len = defproxy.cookie_len;
6307
6308 if (defproxy.capture_name)
6309 curproxy->capture_name = strdup(defproxy.capture_name);
6310 curproxy->capture_namelen = defproxy.capture_namelen;
6311 curproxy->capture_len = defproxy.capture_len;
6312
6313 if (defproxy.errmsg.msg400)
6314 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6315 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6316
6317 if (defproxy.errmsg.msg403)
6318 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6319 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6320
6321 if (defproxy.errmsg.msg408)
6322 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6323 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6324
6325 if (defproxy.errmsg.msg500)
6326 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6327 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6328
6329 if (defproxy.errmsg.msg502)
6330 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6331 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6332
6333 if (defproxy.errmsg.msg503)
6334 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6335 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6336
6337 if (defproxy.errmsg.msg504)
6338 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6339 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6340
willy tarreaua41a8b42005-12-17 14:02:24 +01006341 curproxy->clitimeout = defproxy.clitimeout;
6342 curproxy->contimeout = defproxy.contimeout;
6343 curproxy->srvtimeout = defproxy.srvtimeout;
6344 curproxy->mode = defproxy.mode;
6345 curproxy->logfac1 = defproxy.logfac1;
6346 curproxy->logsrv1 = defproxy.logsrv1;
6347 curproxy->loglev1 = defproxy.loglev1;
6348 curproxy->logfac2 = defproxy.logfac2;
6349 curproxy->logsrv2 = defproxy.logsrv2;
6350 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006351 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006352 curproxy->grace = defproxy.grace;
6353 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006354 curproxy->mon_net = defproxy.mon_net;
6355 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006356 return 0;
6357 }
6358 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006359 /* some variables may have already been initialized earlier */
6360 if (defproxy.check_req) free(defproxy.check_req);
6361 if (defproxy.cookie_name) free(defproxy.cookie_name);
6362 if (defproxy.capture_name) free(defproxy.capture_name);
6363 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6364 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6365 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6366 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6367 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6368 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6369 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6370
6371 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006372 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006373 return 0;
6374 }
6375 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006376 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006377 return -1;
6378 }
6379
willy tarreaua41a8b42005-12-17 14:02:24 +01006380 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6381 if (curproxy == &defproxy) {
6382 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6383 return -1;
6384 }
6385
6386 if (strchr(args[1], ':') == NULL) {
6387 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6388 file, linenum, args[0]);
6389 return -1;
6390 }
6391 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006392 if (!curproxy->listen)
6393 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006394 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006395 return 0;
6396 }
willy tarreaub1285d52005-12-18 01:20:14 +01006397 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6398 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6399 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6400 file, linenum, args[0]);
6401 return -1;
6402 }
6403 /* flush useless bits */
6404 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6405 return 0;
6406 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006407 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006408 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6409 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6410 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6411 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006412 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006413 return -1;
6414 }
6415 }
6416 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006417 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006418 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006419 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6420 curproxy->state = PR_STNEW;
6421 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006422 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6423 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006424// if (curproxy == &defproxy) {
6425// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6426// return -1;
6427// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006428
willy tarreau9fe663a2005-12-17 13:02:59 +01006429 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006430// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6431// file, linenum);
6432// return 0;
6433 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006434 }
6435
6436 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006437 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6438 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006439 return -1;
6440 }
6441 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006442 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006443
6444 cur_arg = 2;
6445 while (*(args[cur_arg])) {
6446 if (!strcmp(args[cur_arg], "rewrite")) {
6447 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006448 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006449 else if (!strcmp(args[cur_arg], "indirect")) {
6450 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006451 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006452 else if (!strcmp(args[cur_arg], "insert")) {
6453 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006454 }
willy tarreau240afa62005-12-17 13:14:35 +01006455 else if (!strcmp(args[cur_arg], "nocache")) {
6456 curproxy->options |= PR_O_COOK_NOC;
6457 }
willy tarreaucd878942005-12-17 13:27:43 +01006458 else if (!strcmp(args[cur_arg], "postonly")) {
6459 curproxy->options |= PR_O_COOK_POST;
6460 }
willy tarreau0174f312005-12-18 01:02:42 +01006461 else if (!strcmp(args[cur_arg], "prefix")) {
6462 curproxy->options |= PR_O_COOK_PFX;
6463 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006464 else {
willy tarreau0174f312005-12-18 01:02:42 +01006465 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006466 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006467 return -1;
6468 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006469 cur_arg++;
6470 }
willy tarreau0174f312005-12-18 01:02:42 +01006471 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6472 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6473 file, linenum);
6474 return -1;
6475 }
6476
6477 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6478 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006479 file, linenum);
6480 return -1;
6481 }
willy tarreau12350152005-12-18 01:03:27 +01006482 }/* end else if (!strcmp(args[0], "cookie")) */
6483 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6484// if (curproxy == &defproxy) {
6485// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6486// return -1;
6487// }
6488
6489 if (curproxy->appsession_name != NULL) {
6490// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6491// file, linenum);
6492// return 0;
6493 free(curproxy->appsession_name);
6494 }
6495
6496 if (*(args[5]) == 0) {
6497 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6498 file, linenum, args[0]);
6499 return -1;
6500 }
6501 have_appsession = 1;
6502 curproxy->appsession_name = strdup(args[1]);
6503 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6504 curproxy->appsession_len = atoi(args[3]);
6505 curproxy->appsession_timeout = atoi(args[5]);
6506 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6507 if (rc) {
6508 Alert("Error Init Appsession Hashtable.\n");
6509 return -1;
6510 }
6511 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006512 else if (!strcmp(args[0], "capture")) {
6513 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6514 // if (curproxy == &defproxy) {
6515 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6516 // return -1;
6517 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006518
willy tarreau4302f492005-12-18 01:00:37 +01006519 if (curproxy->capture_name != NULL) {
6520 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6521 // file, linenum, args[0]);
6522 // return 0;
6523 free(curproxy->capture_name);
6524 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006525
willy tarreau4302f492005-12-18 01:00:37 +01006526 if (*(args[4]) == 0) {
6527 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6528 file, linenum, args[0]);
6529 return -1;
6530 }
6531 curproxy->capture_name = strdup(args[2]);
6532 curproxy->capture_namelen = strlen(curproxy->capture_name);
6533 curproxy->capture_len = atol(args[4]);
6534 if (curproxy->capture_len >= CAPTURE_LEN) {
6535 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6536 file, linenum, CAPTURE_LEN - 1);
6537 curproxy->capture_len = CAPTURE_LEN - 1;
6538 }
6539 curproxy->to_log |= LW_COOKIE;
6540 }
6541 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6542 struct cap_hdr *hdr;
6543
6544 if (curproxy == &defproxy) {
6545 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6546 return -1;
6547 }
6548
6549 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6550 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6551 file, linenum, args[0], args[1]);
6552 return -1;
6553 }
6554
6555 hdr = calloc(sizeof(struct cap_hdr), 1);
6556 hdr->next = curproxy->req_cap;
6557 hdr->name = strdup(args[3]);
6558 hdr->namelen = strlen(args[3]);
6559 hdr->len = atol(args[5]);
6560 hdr->index = curproxy->nb_req_cap++;
6561 curproxy->req_cap = hdr;
6562 curproxy->to_log |= LW_REQHDR;
6563 }
6564 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6565 struct cap_hdr *hdr;
6566
6567 if (curproxy == &defproxy) {
6568 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6569 return -1;
6570 }
6571
6572 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6573 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6574 file, linenum, args[0], args[1]);
6575 return -1;
6576 }
6577 hdr = calloc(sizeof(struct cap_hdr), 1);
6578 hdr->next = curproxy->rsp_cap;
6579 hdr->name = strdup(args[3]);
6580 hdr->namelen = strlen(args[3]);
6581 hdr->len = atol(args[5]);
6582 hdr->index = curproxy->nb_rsp_cap++;
6583 curproxy->rsp_cap = hdr;
6584 curproxy->to_log |= LW_RSPHDR;
6585 }
6586 else {
6587 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006588 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006589 return -1;
6590 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006591 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006592 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006593 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006594 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006595 return 0;
6596 }
6597 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006598 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6599 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006600 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006601 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006602 curproxy->contimeout = atol(args[1]);
6603 }
6604 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006605 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006606 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6607 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006608 return 0;
6609 }
6610 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006611 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6612 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006613 return -1;
6614 }
6615 curproxy->clitimeout = atol(args[1]);
6616 }
6617 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006618 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006619 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006620 return 0;
6621 }
6622 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006623 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6624 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006625 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006626 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006627 curproxy->srvtimeout = atol(args[1]);
6628 }
6629 else if (!strcmp(args[0], "retries")) { /* connection retries */
6630 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006631 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6632 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006633 return -1;
6634 }
6635 curproxy->conn_retries = atol(args[1]);
6636 }
6637 else if (!strcmp(args[0], "option")) {
6638 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006639 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006640 return -1;
6641 }
6642 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006643 /* enable reconnections to dispatch */
6644 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006645#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006646 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006647 /* enable transparent proxy connections */
6648 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006649#endif
6650 else if (!strcmp(args[1], "keepalive"))
6651 /* enable keep-alive */
6652 curproxy->options |= PR_O_KEEPALIVE;
6653 else if (!strcmp(args[1], "forwardfor"))
6654 /* insert x-forwarded-for field */
6655 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006656 else if (!strcmp(args[1], "logasap"))
6657 /* log as soon as possible, without waiting for the session to complete */
6658 curproxy->options |= PR_O_LOGASAP;
6659 else if (!strcmp(args[1], "httpclose"))
6660 /* force connection: close in both directions in HTTP mode */
6661 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01006662 else if (!strcmp(args[1], "forceclose"))
6663 /* force connection: close in both directions in HTTP mode and enforce end of session */
6664 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006665 else if (!strcmp(args[1], "checkcache"))
6666 /* require examination of cacheability of the 'set-cookie' field */
6667 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006668 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006669 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006670 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006671 else if (!strcmp(args[1], "tcplog"))
6672 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006673 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006674 else if (!strcmp(args[1], "dontlognull")) {
6675 /* don't log empty requests */
6676 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006677 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006678 else if (!strcmp(args[1], "tcpka")) {
6679 /* enable TCP keep-alives on client and server sessions */
6680 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6681 }
6682 else if (!strcmp(args[1], "clitcpka")) {
6683 /* enable TCP keep-alives on client sessions */
6684 curproxy->options |= PR_O_TCP_CLI_KA;
6685 }
6686 else if (!strcmp(args[1], "srvtcpka")) {
6687 /* enable TCP keep-alives on server sessions */
6688 curproxy->options |= PR_O_TCP_SRV_KA;
6689 }
Willy TARREAU3481c462006-03-01 22:37:57 +01006690 else if (!strcmp(args[1], "allbackups")) {
6691 /* Use all backup servers simultaneously */
6692 curproxy->options |= PR_O_USE_ALL_BK;
6693 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006694 else if (!strcmp(args[1], "httpchk")) {
6695 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006696 if (curproxy->check_req != NULL) {
6697 free(curproxy->check_req);
6698 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006699 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006700 if (!*args[2]) { /* no argument */
6701 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6702 curproxy->check_len = strlen(DEF_CHECK_REQ);
6703 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006704 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6705 curproxy->check_req = (char *)malloc(reqlen);
6706 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6707 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006708 } else { /* more arguments : METHOD URI [HTTP_VER] */
6709 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6710 if (*args[4])
6711 reqlen += strlen(args[4]);
6712 else
6713 reqlen += strlen("HTTP/1.0");
6714
6715 curproxy->check_req = (char *)malloc(reqlen);
6716 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6717 "%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 +01006718 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006719 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006720 else if (!strcmp(args[1], "persist")) {
6721 /* persist on using the server specified by the cookie, even when it's down */
6722 curproxy->options |= PR_O_PERSIST;
6723 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006724 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006725 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006726 return -1;
6727 }
6728 return 0;
6729 }
6730 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6731 /* enable reconnections to dispatch */
6732 curproxy->options |= PR_O_REDISP;
6733 }
willy tarreaua1598082005-12-17 13:08:06 +01006734#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006735 else if (!strcmp(args[0], "transparent")) {
6736 /* enable transparent proxy connections */
6737 curproxy->options |= PR_O_TRANSP;
6738 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006739#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006740 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6741 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006742 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006743 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006744 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006745 curproxy->maxconn = atol(args[1]);
6746 }
6747 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6748 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006749 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006750 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006751 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006752 curproxy->grace = atol(args[1]);
6753 }
6754 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006755 if (curproxy == &defproxy) {
6756 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6757 return -1;
6758 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006759 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006760 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006761 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006762 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006763 curproxy->dispatch_addr = *str2sa(args[1]);
6764 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006765 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006766 if (*(args[1])) {
6767 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006768 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006769 }
6770 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006771 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006772 return -1;
6773 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006774 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006775 else /* if no option is set, use round-robin by default */
6776 curproxy->options |= PR_O_BALANCE_RR;
6777 }
6778 else if (!strcmp(args[0], "server")) { /* server address */
6779 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006780 char *rport;
6781 char *raddr;
6782 short realport;
6783 int do_check;
6784
6785 if (curproxy == &defproxy) {
6786 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6787 return -1;
6788 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006789
willy tarreaua41a8b42005-12-17 14:02:24 +01006790 if (!*args[2]) {
6791 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006792 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006793 return -1;
6794 }
6795 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6796 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6797 return -1;
6798 }
willy tarreau0174f312005-12-18 01:02:42 +01006799
6800 if (curproxy->srv == NULL)
6801 curproxy->srv = newsrv;
6802 else
6803 curproxy->cursrv->next = newsrv;
6804 curproxy->cursrv = newsrv;
6805
6806 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006807 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006808
6809 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006810 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006811 newsrv->id = strdup(args[1]);
6812
6813 /* several ways to check the port component :
6814 * - IP => port=+0, relative
6815 * - IP: => port=+0, relative
6816 * - IP:N => port=N, absolute
6817 * - IP:+N => port=+N, relative
6818 * - IP:-N => port=-N, relative
6819 */
6820 raddr = strdup(args[2]);
6821 rport = strchr(raddr, ':');
6822 if (rport) {
6823 *rport++ = 0;
6824 realport = atol(rport);
6825 if (!isdigit((int)*rport))
6826 newsrv->state |= SRV_MAPPORTS;
6827 } else {
6828 realport = 0;
6829 newsrv->state |= SRV_MAPPORTS;
6830 }
6831
6832 newsrv->addr = *str2sa(raddr);
6833 newsrv->addr.sin_port = htons(realport);
6834 free(raddr);
6835
willy tarreau9fe663a2005-12-17 13:02:59 +01006836 newsrv->curfd = -1; /* no health-check in progress */
6837 newsrv->inter = DEF_CHKINTR;
6838 newsrv->rise = DEF_RISETIME;
6839 newsrv->fall = DEF_FALLTIME;
6840 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
6841 cur_arg = 3;
6842 while (*args[cur_arg]) {
6843 if (!strcmp(args[cur_arg], "cookie")) {
6844 newsrv->cookie = strdup(args[cur_arg + 1]);
6845 newsrv->cklen = strlen(args[cur_arg + 1]);
6846 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006847 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006848 else if (!strcmp(args[cur_arg], "rise")) {
6849 newsrv->rise = atol(args[cur_arg + 1]);
6850 newsrv->health = newsrv->rise;
6851 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006852 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006853 else if (!strcmp(args[cur_arg], "fall")) {
6854 newsrv->fall = atol(args[cur_arg + 1]);
6855 cur_arg += 2;
6856 }
6857 else if (!strcmp(args[cur_arg], "inter")) {
6858 newsrv->inter = atol(args[cur_arg + 1]);
6859 cur_arg += 2;
6860 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006861 else if (!strcmp(args[cur_arg], "port")) {
6862 newsrv->check_port = atol(args[cur_arg + 1]);
6863 cur_arg += 2;
6864 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006865 else if (!strcmp(args[cur_arg], "backup")) {
6866 newsrv->state |= SRV_BACKUP;
6867 cur_arg ++;
6868 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006869 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01006870 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006871 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006872 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006873 }
willy tarreau0174f312005-12-18 01:02:42 +01006874 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
6875 if (!*args[cur_arg + 1]) {
6876 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
6877 file, linenum, "source");
6878 return -1;
6879 }
6880 newsrv->state |= SRV_BIND_SRC;
6881 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
6882 cur_arg += 2;
6883 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006884 else {
willy tarreau0174f312005-12-18 01:02:42 +01006885 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port' and 'source'.\n",
willy tarreaua41a8b42005-12-17 14:02:24 +01006886 file, linenum, newsrv->id);
6887 return -1;
6888 }
6889 }
6890
6891 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006892 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
6893 newsrv->check_port = realport; /* by default */
6894 if (!newsrv->check_port) {
6895 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 +01006896 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006897 return -1;
6898 }
Willy TARREAU3759f982006-03-01 22:44:17 +01006899 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006900 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006901
willy tarreau9fe663a2005-12-17 13:02:59 +01006902 curproxy->nbservers++;
6903 }
6904 else if (!strcmp(args[0], "log")) { /* syslog server address */
6905 struct sockaddr_in *sa;
6906 int facility;
6907
6908 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
6909 curproxy->logfac1 = global.logfac1;
6910 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006911 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006912 curproxy->logfac2 = global.logfac2;
6913 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01006914 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01006915 }
6916 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01006917 int level;
6918
willy tarreau0f7af912005-12-17 12:21:26 +01006919 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6920 if (!strcmp(log_facilities[facility], args[2]))
6921 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01006922
willy tarreau0f7af912005-12-17 12:21:26 +01006923 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006924 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01006925 exit(1);
6926 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006927
willy tarreau8337c6b2005-12-17 13:41:01 +01006928 level = 7; /* max syslog level = debug */
6929 if (*(args[3])) {
6930 while (level >= 0 && strcmp(log_levels[level], args[3]))
6931 level--;
6932 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006933 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006934 exit(1);
6935 }
6936 }
6937
willy tarreau0f7af912005-12-17 12:21:26 +01006938 sa = str2sa(args[1]);
6939 if (!sa->sin_port)
6940 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01006941
willy tarreau0f7af912005-12-17 12:21:26 +01006942 if (curproxy->logfac1 == -1) {
6943 curproxy->logsrv1 = *sa;
6944 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006945 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006946 }
6947 else if (curproxy->logfac2 == -1) {
6948 curproxy->logsrv2 = *sa;
6949 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006950 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006951 }
6952 else {
6953 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006954 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006955 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006956 }
6957 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006958 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006959 file, linenum);
6960 return -1;
6961 }
6962 }
willy tarreaua1598082005-12-17 13:08:06 +01006963 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01006964 if (!*args[1]) {
6965 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006966 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01006967 return -1;
6968 }
6969
6970 curproxy->source_addr = *str2sa(args[1]);
6971 curproxy->options |= PR_O_BIND_SRC;
6972 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006973 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
6974 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006975 if (curproxy == &defproxy) {
6976 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6977 return -1;
6978 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006979
6980 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006981 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6982 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006983 return -1;
6984 }
6985
6986 preg = calloc(1, sizeof(regex_t));
6987 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006988 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006989 return -1;
6990 }
6991
willy tarreauc1f47532005-12-18 01:08:26 +01006992 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6993 if (err) {
6994 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6995 file, linenum, *err);
6996 return -1;
6997 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006998 }
6999 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7000 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007001 if (curproxy == &defproxy) {
7002 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7003 return -1;
7004 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007005
7006 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007007 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007008 return -1;
7009 }
7010
7011 preg = calloc(1, sizeof(regex_t));
7012 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007013 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007014 return -1;
7015 }
7016
7017 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7018 }
7019 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7020 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007021 if (curproxy == &defproxy) {
7022 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7023 return -1;
7024 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007025
7026 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007027 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007028 return -1;
7029 }
7030
7031 preg = calloc(1, sizeof(regex_t));
7032 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007033 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007034 return -1;
7035 }
7036
7037 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7038 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007039 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7040 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007041 if (curproxy == &defproxy) {
7042 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7043 return -1;
7044 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007045
7046 if (*(args[1]) == 0) {
7047 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7048 return -1;
7049 }
7050
7051 preg = calloc(1, sizeof(regex_t));
7052 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7053 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7054 return -1;
7055 }
7056
7057 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7058 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007059 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7060 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007061 if (curproxy == &defproxy) {
7062 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7063 return -1;
7064 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007065
7066 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007067 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007068 return -1;
7069 }
7070
7071 preg = calloc(1, sizeof(regex_t));
7072 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007073 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007074 return -1;
7075 }
7076
7077 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7078 }
7079 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7080 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007081 if (curproxy == &defproxy) {
7082 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7083 return -1;
7084 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007085
7086 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007087 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7088 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007089 return -1;
7090 }
7091
7092 preg = calloc(1, sizeof(regex_t));
7093 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007094 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007095 return -1;
7096 }
7097
willy tarreauc1f47532005-12-18 01:08:26 +01007098 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7099 if (err) {
7100 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7101 file, linenum, *err);
7102 return -1;
7103 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007104 }
7105 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7106 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007107 if (curproxy == &defproxy) {
7108 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7109 return -1;
7110 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007111
7112 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007113 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007114 return -1;
7115 }
7116
7117 preg = calloc(1, sizeof(regex_t));
7118 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007119 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007120 return -1;
7121 }
7122
7123 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7124 }
7125 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7126 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007127 if (curproxy == &defproxy) {
7128 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7129 return -1;
7130 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007131
7132 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007133 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007134 return -1;
7135 }
7136
7137 preg = calloc(1, sizeof(regex_t));
7138 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007139 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007140 return -1;
7141 }
7142
7143 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7144 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007145 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7146 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007147 if (curproxy == &defproxy) {
7148 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7149 return -1;
7150 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007151
7152 if (*(args[1]) == 0) {
7153 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7154 return -1;
7155 }
7156
7157 preg = calloc(1, sizeof(regex_t));
7158 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7159 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7160 return -1;
7161 }
7162
7163 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7164 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007165 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7166 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007167 if (curproxy == &defproxy) {
7168 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7169 return -1;
7170 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007171
7172 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007173 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007174 return -1;
7175 }
7176
7177 preg = calloc(1, sizeof(regex_t));
7178 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007179 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007180 return -1;
7181 }
7182
7183 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7184 }
7185 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007186 if (curproxy == &defproxy) {
7187 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7188 return -1;
7189 }
7190
willy tarreau9fe663a2005-12-17 13:02:59 +01007191 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007192 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007193 return 0;
7194 }
7195
7196 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007197 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007198 return -1;
7199 }
7200
willy tarreau4302f492005-12-18 01:00:37 +01007201 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7202 }
7203 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7204 regex_t *preg;
7205
7206 if (*(args[1]) == 0 || *(args[2]) == 0) {
7207 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7208 file, linenum, args[0]);
7209 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007210 }
willy tarreau4302f492005-12-18 01:00:37 +01007211
7212 preg = calloc(1, sizeof(regex_t));
7213 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7214 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7215 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007216 }
willy tarreau4302f492005-12-18 01:00:37 +01007217
willy tarreauc1f47532005-12-18 01:08:26 +01007218 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7219 if (err) {
7220 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7221 file, linenum, *err);
7222 return -1;
7223 }
willy tarreau4302f492005-12-18 01:00:37 +01007224 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007225 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7226 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007227 if (curproxy == &defproxy) {
7228 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7229 return -1;
7230 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007231
7232 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007233 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007234 return -1;
7235 }
willy tarreaue39cd132005-12-17 13:00:18 +01007236
willy tarreau9fe663a2005-12-17 13:02:59 +01007237 preg = calloc(1, sizeof(regex_t));
7238 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007239 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007240 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007241 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007242
willy tarreauc1f47532005-12-18 01:08:26 +01007243 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7244 if (err) {
7245 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7246 file, linenum, *err);
7247 return -1;
7248 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007249 }
willy tarreau982249e2005-12-18 00:57:06 +01007250 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7251 regex_t *preg;
7252 if (curproxy == &defproxy) {
7253 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7254 return -1;
7255 }
7256
7257 if (*(args[1]) == 0) {
7258 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7259 return -1;
7260 }
7261
7262 preg = calloc(1, sizeof(regex_t));
7263 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7264 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7265 return -1;
7266 }
7267
willy tarreauc1f47532005-12-18 01:08:26 +01007268 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7269 if (err) {
7270 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7271 file, linenum, *err);
7272 return -1;
7273 }
willy tarreau982249e2005-12-18 00:57:06 +01007274 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007275 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007276 regex_t *preg;
7277 if (curproxy == &defproxy) {
7278 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7279 return -1;
7280 }
willy tarreaue39cd132005-12-17 13:00:18 +01007281
willy tarreaua41a8b42005-12-17 14:02:24 +01007282 if (*(args[1]) == 0 || *(args[2]) == 0) {
7283 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7284 file, linenum, args[0]);
7285 return -1;
7286 }
willy tarreaue39cd132005-12-17 13:00:18 +01007287
willy tarreaua41a8b42005-12-17 14:02:24 +01007288 preg = calloc(1, sizeof(regex_t));
7289 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7290 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7291 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007292 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007293
willy tarreauc1f47532005-12-18 01:08:26 +01007294 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7295 if (err) {
7296 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7297 file, linenum, *err);
7298 return -1;
7299 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007300 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007301 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7302 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007303 if (curproxy == &defproxy) {
7304 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7305 return -1;
7306 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007307
7308 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007309 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007310 return -1;
7311 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007312
willy tarreau9fe663a2005-12-17 13:02:59 +01007313 preg = calloc(1, sizeof(regex_t));
7314 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007315 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007316 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007317 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007318
willy tarreauc1f47532005-12-18 01:08:26 +01007319 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7320 if (err) {
7321 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7322 file, linenum, *err);
7323 return -1;
7324 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007325 }
willy tarreau982249e2005-12-18 00:57:06 +01007326 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7327 regex_t *preg;
7328 if (curproxy == &defproxy) {
7329 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7330 return -1;
7331 }
7332
7333 if (*(args[1]) == 0) {
7334 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7335 return -1;
7336 }
7337
7338 preg = calloc(1, sizeof(regex_t));
7339 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7340 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7341 return -1;
7342 }
7343
willy tarreauc1f47532005-12-18 01:08:26 +01007344 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7345 if (err) {
7346 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7347 file, linenum, *err);
7348 return -1;
7349 }
willy tarreau982249e2005-12-18 00:57:06 +01007350 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007351 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007352 if (curproxy == &defproxy) {
7353 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7354 return -1;
7355 }
7356
willy tarreau9fe663a2005-12-17 13:02:59 +01007357 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007358 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007359 return 0;
7360 }
7361
7362 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007363 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007364 return -1;
7365 }
7366
7367 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7368 }
willy tarreauc1f47532005-12-18 01:08:26 +01007369 else if (!strcmp(args[0], "errorloc") ||
7370 !strcmp(args[0], "errorloc302") ||
7371 !strcmp(args[0], "errorloc303")) { /* error location */
7372 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007373 char *err;
7374
willy tarreaueedaa9f2005-12-17 14:08:03 +01007375 // if (curproxy == &defproxy) {
7376 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7377 // return -1;
7378 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007379
willy tarreau8337c6b2005-12-17 13:41:01 +01007380 if (*(args[2]) == 0) {
7381 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7382 return -1;
7383 }
7384
7385 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007386 if (!strcmp(args[0], "errorloc303")) {
7387 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7388 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7389 } else {
7390 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7391 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7392 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007393
7394 if (errnum == 400) {
7395 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007396 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007397 free(curproxy->errmsg.msg400);
7398 }
7399 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007400 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007401 }
7402 else if (errnum == 403) {
7403 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007404 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007405 free(curproxy->errmsg.msg403);
7406 }
7407 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007408 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007409 }
7410 else if (errnum == 408) {
7411 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007412 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007413 free(curproxy->errmsg.msg408);
7414 }
7415 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007416 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007417 }
7418 else if (errnum == 500) {
7419 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007420 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007421 free(curproxy->errmsg.msg500);
7422 }
7423 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007424 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007425 }
7426 else if (errnum == 502) {
7427 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007428 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007429 free(curproxy->errmsg.msg502);
7430 }
7431 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007432 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007433 }
7434 else if (errnum == 503) {
7435 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007436 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007437 free(curproxy->errmsg.msg503);
7438 }
7439 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007440 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007441 }
7442 else if (errnum == 504) {
7443 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007444 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007445 free(curproxy->errmsg.msg504);
7446 }
7447 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007448 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007449 }
7450 else {
7451 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7452 free(err);
7453 }
7454 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007455 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007456 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007457 return -1;
7458 }
7459 return 0;
7460}
willy tarreaue39cd132005-12-17 13:00:18 +01007461
willy tarreau5cbea6f2005-12-17 12:48:26 +01007462
willy tarreau9fe663a2005-12-17 13:02:59 +01007463/*
7464 * This function reads and parses the configuration file given in the argument.
7465 * returns 0 if OK, -1 if error.
7466 */
7467int readcfgfile(char *file) {
7468 char thisline[256];
7469 char *line;
7470 FILE *f;
7471 int linenum = 0;
7472 char *end;
7473 char *args[MAX_LINE_ARGS];
7474 int arg;
7475 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007476 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007477 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007478
willy tarreau9fe663a2005-12-17 13:02:59 +01007479 struct proxy *curproxy = NULL;
7480 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007481
willy tarreau9fe663a2005-12-17 13:02:59 +01007482 if ((f=fopen(file,"r")) == NULL)
7483 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007484
willy tarreaueedaa9f2005-12-17 14:08:03 +01007485 init_default_instance();
7486
willy tarreau9fe663a2005-12-17 13:02:59 +01007487 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7488 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007489
willy tarreau9fe663a2005-12-17 13:02:59 +01007490 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007491
willy tarreau9fe663a2005-12-17 13:02:59 +01007492 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007493 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007494 line++;
7495
7496 arg = 0;
7497 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007498
willy tarreau9fe663a2005-12-17 13:02:59 +01007499 while (*line && arg < MAX_LINE_ARGS) {
7500 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7501 * C equivalent value. Other combinations left unchanged (eg: \1).
7502 */
7503 if (*line == '\\') {
7504 int skip = 0;
7505 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7506 *line = line[1];
7507 skip = 1;
7508 }
7509 else if (line[1] == 'r') {
7510 *line = '\r';
7511 skip = 1;
7512 }
7513 else if (line[1] == 'n') {
7514 *line = '\n';
7515 skip = 1;
7516 }
7517 else if (line[1] == 't') {
7518 *line = '\t';
7519 skip = 1;
7520 }
willy tarreauc1f47532005-12-18 01:08:26 +01007521 else if (line[1] == 'x') {
7522 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7523 unsigned char hex1, hex2;
7524 hex1 = toupper(line[2]) - '0';
7525 hex2 = toupper(line[3]) - '0';
7526 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7527 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7528 *line = (hex1<<4) + hex2;
7529 skip = 3;
7530 }
7531 else {
7532 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7533 return -1;
7534 }
7535 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007536 if (skip) {
7537 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7538 end -= skip;
7539 }
7540 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007541 }
willy tarreaua1598082005-12-17 13:08:06 +01007542 else if (*line == '#' || *line == '\n' || *line == '\r') {
7543 /* end of string, end of loop */
7544 *line = 0;
7545 break;
7546 }
willy tarreauc29948c2005-12-17 13:10:27 +01007547 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007548 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007549 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007550 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007551 line++;
7552 args[++arg] = line;
7553 }
7554 else {
7555 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007556 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007557 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007558
willy tarreau9fe663a2005-12-17 13:02:59 +01007559 /* empty line */
7560 if (!**args)
7561 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007562
willy tarreau9fe663a2005-12-17 13:02:59 +01007563 /* zero out remaining args */
7564 while (++arg < MAX_LINE_ARGS) {
7565 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007566 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007567
willy tarreaua41a8b42005-12-17 14:02:24 +01007568 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007569 confsect = CFG_LISTEN;
7570 else if (!strcmp(args[0], "global")) /* global config */
7571 confsect = CFG_GLOBAL;
7572 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007573
willy tarreau9fe663a2005-12-17 13:02:59 +01007574 switch (confsect) {
7575 case CFG_LISTEN:
7576 if (cfg_parse_listen(file, linenum, args) < 0)
7577 return -1;
7578 break;
7579 case CFG_GLOBAL:
7580 if (cfg_parse_global(file, linenum, args) < 0)
7581 return -1;
7582 break;
7583 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007584 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007585 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007586 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007587
7588
willy tarreau0f7af912005-12-17 12:21:26 +01007589 }
7590 fclose(f);
7591
7592 /*
7593 * Now, check for the integrity of all that we have collected.
7594 */
7595
Willy TARREAU3759f982006-03-01 22:44:17 +01007596 /* will be needed further to delay some tasks */
7597 tv_now(&now);
7598
willy tarreau0f7af912005-12-17 12:21:26 +01007599 if ((curproxy = proxy) == NULL) {
7600 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7601 file);
7602 return -1;
7603 }
7604
7605 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007606 curproxy->cursrv = NULL;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007607 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007608 curproxy = curproxy->next;
7609 continue;
7610 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007611
7612 if (curproxy->listen == NULL) {
7613 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);
7614 cfgerr++;
7615 }
7616 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007617 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007618 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007619 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7620 file, curproxy->id);
7621 cfgerr++;
7622 }
7623 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7624 if (curproxy->options & PR_O_TRANSP) {
7625 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7626 file, curproxy->id);
7627 cfgerr++;
7628 }
7629 else if (curproxy->srv == NULL) {
7630 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7631 file, curproxy->id);
7632 cfgerr++;
7633 }
willy tarreaua1598082005-12-17 13:08:06 +01007634 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007635 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7636 file, curproxy->id);
7637 }
7638 }
7639 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007640 if (curproxy->cookie_name != NULL) {
7641 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7642 file, curproxy->id);
7643 }
7644 if ((newsrv = curproxy->srv) != NULL) {
7645 Warning("parsing %s : servers will be ignored for listener %s.\n",
7646 file, curproxy->id);
7647 }
willy tarreaue39cd132005-12-17 13:00:18 +01007648 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007649 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7650 file, curproxy->id);
7651 }
willy tarreaue39cd132005-12-17 13:00:18 +01007652 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007653 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7654 file, curproxy->id);
7655 }
7656 }
7657 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7658 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7659 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7660 file, curproxy->id);
7661 cfgerr++;
7662 }
7663 else {
7664 while (newsrv != NULL) {
7665 /* nothing to check for now */
7666 newsrv = newsrv->next;
7667 }
7668 }
7669 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007670
7671 if (curproxy->options & PR_O_LOGASAP)
7672 curproxy->to_log &= ~LW_BYTES;
7673
willy tarreau8337c6b2005-12-17 13:41:01 +01007674 if (curproxy->errmsg.msg400 == NULL) {
7675 curproxy->errmsg.msg400 = (char *)HTTP_400;
7676 curproxy->errmsg.len400 = strlen(HTTP_400);
7677 }
7678 if (curproxy->errmsg.msg403 == NULL) {
7679 curproxy->errmsg.msg403 = (char *)HTTP_403;
7680 curproxy->errmsg.len403 = strlen(HTTP_403);
7681 }
7682 if (curproxy->errmsg.msg408 == NULL) {
7683 curproxy->errmsg.msg408 = (char *)HTTP_408;
7684 curproxy->errmsg.len408 = strlen(HTTP_408);
7685 }
7686 if (curproxy->errmsg.msg500 == NULL) {
7687 curproxy->errmsg.msg500 = (char *)HTTP_500;
7688 curproxy->errmsg.len500 = strlen(HTTP_500);
7689 }
7690 if (curproxy->errmsg.msg502 == NULL) {
7691 curproxy->errmsg.msg502 = (char *)HTTP_502;
7692 curproxy->errmsg.len502 = strlen(HTTP_502);
7693 }
7694 if (curproxy->errmsg.msg503 == NULL) {
7695 curproxy->errmsg.msg503 = (char *)HTTP_503;
7696 curproxy->errmsg.len503 = strlen(HTTP_503);
7697 }
7698 if (curproxy->errmsg.msg504 == NULL) {
7699 curproxy->errmsg.msg504 = (char *)HTTP_504;
7700 curproxy->errmsg.len504 = strlen(HTTP_504);
7701 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007702
7703 /* now we'll start this proxy's health checks if any */
7704 /* 1- count the checkers to run simultaneously */
7705 nbchk = 0;
7706 mininter = 0;
7707 newsrv = curproxy->srv;
7708 while (newsrv != NULL) {
7709 if (newsrv->state & SRV_CHECKED) {
7710 if (!mininter || mininter > newsrv->inter)
7711 mininter = newsrv->inter;
7712 nbchk++;
7713 }
7714 newsrv = newsrv->next;
7715 }
7716
7717 /* 2- start them as far as possible from each others while respecting
7718 * their own intervals. For this, we will start them after their own
7719 * interval added to the min interval divided by the number of servers,
7720 * weighted by the server's position in the list.
7721 */
7722 if (nbchk > 0) {
7723 struct task *t;
7724 int srvpos;
7725
7726 newsrv = curproxy->srv;
7727 srvpos = 0;
7728 while (newsrv != NULL) {
7729 /* should this server be checked ? */
7730 if (newsrv->state & SRV_CHECKED) {
7731 if ((t = pool_alloc(task)) == NULL) {
7732 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7733 return -1;
7734 }
7735
7736 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
7737 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
7738 t->state = TASK_IDLE;
7739 t->process = process_chk;
7740 t->context = newsrv;
7741
7742 /* check this every ms */
7743 tv_delayfrom(&t->expire, &now,
7744 newsrv->inter + mininter * srvpos / nbchk);
7745 task_queue(t);
7746 //task_wakeup(&rq, t);
7747 srvpos++;
7748 }
7749 newsrv = newsrv->next;
7750 }
7751 }
7752
willy tarreau0f7af912005-12-17 12:21:26 +01007753 curproxy = curproxy->next;
7754 }
7755 if (cfgerr > 0) {
7756 Alert("Errors found in configuration file, aborting.\n");
7757 return -1;
7758 }
7759 else
7760 return 0;
7761}
7762
7763
7764/*
7765 * This function initializes all the necessary variables. It only returns
7766 * if everything is OK. If something fails, it exits.
7767 */
7768void init(int argc, char **argv) {
7769 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007770 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007771 char *old_argv = *argv;
7772 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007773 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007774
7775 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007776 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007777 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007778 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007779 exit(1);
7780 }
7781
Willy TARREAUa9e75f62006-03-01 22:27:48 +01007782 /* initialize the libc's localtime structures once for all so that we
7783 * won't be missing memory if we want to send alerts under OOM conditions.
7784 */
7785 tv_now(&now);
7786 localtime(&now.tv_sec);
7787
willy tarreau4302f492005-12-18 01:00:37 +01007788 /* initialize the log header encoding map : '{|}"#' should be encoded with
7789 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7790 * URL encoding only requires '"', '#' to be encoded as well as non-
7791 * printable characters above.
7792 */
7793 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7794 memset(url_encode_map, 0, sizeof(url_encode_map));
7795 for (i = 0; i < 32; i++) {
7796 FD_SET(i, hdr_encode_map);
7797 FD_SET(i, url_encode_map);
7798 }
7799 for (i = 127; i < 256; i++) {
7800 FD_SET(i, hdr_encode_map);
7801 FD_SET(i, url_encode_map);
7802 }
7803
7804 tmp = "\"#{|}";
7805 while (*tmp) {
7806 FD_SET(*tmp, hdr_encode_map);
7807 tmp++;
7808 }
7809
7810 tmp = "\"#";
7811 while (*tmp) {
7812 FD_SET(*tmp, url_encode_map);
7813 tmp++;
7814 }
7815
willy tarreau64a3cc32005-12-18 01:13:11 +01007816 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
7817#if defined(ENABLE_POLL)
7818 cfg_polling_mechanism |= POLL_USE_POLL;
7819#endif
7820#if defined(ENABLE_EPOLL)
7821 cfg_polling_mechanism |= POLL_USE_EPOLL;
7822#endif
7823
willy tarreau0f7af912005-12-17 12:21:26 +01007824 pid = getpid();
7825 progname = *argv;
7826 while ((tmp = strchr(progname, '/')) != NULL)
7827 progname = tmp + 1;
7828
7829 argc--; argv++;
7830 while (argc > 0) {
7831 char *flag;
7832
7833 if (**argv == '-') {
7834 flag = *argv+1;
7835
7836 /* 1 arg */
7837 if (*flag == 'v') {
7838 display_version();
7839 exit(0);
7840 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007841#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007842 else if (*flag == 'd' && flag[1] == 'e')
7843 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007844#endif
7845#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007846 else if (*flag == 'd' && flag[1] == 'p')
7847 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007848#endif
willy tarreau982249e2005-12-18 00:57:06 +01007849 else if (*flag == 'V')
7850 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01007851 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01007852 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01007853 else if (*flag == 'c')
7854 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01007855 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01007856 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007857 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01007858 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01007859#if STATTIME > 0
7860 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01007861 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01007862 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01007863 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01007864#endif
7865 else { /* >=2 args */
7866 argv++; argc--;
7867 if (argc == 0)
7868 usage(old_argv);
7869
7870 switch (*flag) {
7871 case 'n' : cfg_maxconn = atol(*argv); break;
7872 case 'N' : cfg_maxpconn = atol(*argv); break;
7873 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007874 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01007875 default: usage(old_argv);
7876 }
7877 }
7878 }
7879 else
7880 usage(old_argv);
7881 argv++; argc--;
7882 }
7883
willy tarreaud0fb4652005-12-18 01:32:04 +01007884 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
7885 (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01007886
willy tarreau0f7af912005-12-17 12:21:26 +01007887 if (!cfg_cfgfile)
7888 usage(old_argv);
7889
7890 gethostname(hostname, MAX_HOSTNAME_LEN);
7891
willy tarreau12350152005-12-18 01:03:27 +01007892 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007893 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01007894 if (readcfgfile(cfg_cfgfile) < 0) {
7895 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
7896 exit(1);
7897 }
willy tarreau12350152005-12-18 01:03:27 +01007898 if (have_appsession)
7899 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01007900
willy tarreau982249e2005-12-18 00:57:06 +01007901 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01007902 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
7903 exit(0);
7904 }
7905
willy tarreau9fe663a2005-12-17 13:02:59 +01007906 if (cfg_maxconn > 0)
7907 global.maxconn = cfg_maxconn;
7908
willy tarreaufe2c5c12005-12-17 14:14:34 +01007909 if (cfg_pidfile) {
7910 if (global.pidfile)
7911 free(global.pidfile);
7912 global.pidfile = strdup(cfg_pidfile);
7913 }
7914
willy tarreau9fe663a2005-12-17 13:02:59 +01007915 if (global.maxconn == 0)
7916 global.maxconn = DEFAULT_MAXCONN;
7917
Willy TARREAU203b0b62006-03-12 18:00:28 +01007918 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01007919
7920 if (arg_mode & MODE_DEBUG) {
7921 /* command line debug mode inhibits configuration mode */
7922 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7923 }
willy tarreau982249e2005-12-18 00:57:06 +01007924 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
7925 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01007926
7927 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
7928 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
7929 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7930 }
7931
7932 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
7933 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
7934 global.nbproc = 1;
7935 }
7936
7937 if (global.nbproc < 1)
7938 global.nbproc = 1;
7939
willy tarreau0f7af912005-12-17 12:21:26 +01007940 StaticReadEvent = (fd_set *)calloc(1,
7941 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007942 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007943 StaticWriteEvent = (fd_set *)calloc(1,
7944 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007945 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007946
7947 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01007948 sizeof(struct fdtab) * (global.maxsock));
7949 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01007950 fdtab[i].state = FD_STCLOSE;
7951 }
7952}
7953
7954/*
7955 * this function starts all the proxies. It returns 0 if OK, -1 if not.
7956 */
7957int start_proxies() {
7958 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007959 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01007960 int fd;
7961
7962 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007963 if (curproxy->state == PR_STSTOPPED)
willy tarreau0f7af912005-12-17 12:21:26 +01007964 continue;
7965
willy tarreaua41a8b42005-12-17 14:02:24 +01007966 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
7967 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01007968 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007969 Alert("cannot create listening socket for proxy %s. Aborting.\n",
7970 curproxy->id);
7971 return -1;
7972 }
willy tarreau0f7af912005-12-17 12:21:26 +01007973
willy tarreaua41a8b42005-12-17 14:02:24 +01007974 if (fd >= global.maxsock) {
7975 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
7976 curproxy->id);
7977 close(fd);
7978 return -1;
7979 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007980
willy tarreaua41a8b42005-12-17 14:02:24 +01007981 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
7982 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
7983 (char *) &one, sizeof(one)) == -1)) {
7984 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
7985 curproxy->id);
7986 close(fd);
7987 return -1;
7988 }
willy tarreau0f7af912005-12-17 12:21:26 +01007989
willy tarreaua41a8b42005-12-17 14:02:24 +01007990 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
7991 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
7992 curproxy->id);
7993 }
willy tarreau0f7af912005-12-17 12:21:26 +01007994
willy tarreaua41a8b42005-12-17 14:02:24 +01007995 if (bind(fd,
7996 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01007997 listener->addr.ss_family == AF_INET6 ?
7998 sizeof(struct sockaddr_in6) :
7999 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008000 Alert("cannot bind socket for proxy %s. Aborting.\n",
8001 curproxy->id);
8002 close(fd);
8003 return -1;
8004 }
willy tarreau0f7af912005-12-17 12:21:26 +01008005
willy tarreaua41a8b42005-12-17 14:02:24 +01008006 if (listen(fd, curproxy->maxconn) == -1) {
8007 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8008 curproxy->id);
8009 close(fd);
8010 return -1;
8011 }
willy tarreau0f7af912005-12-17 12:21:26 +01008012
willy tarreaua41a8b42005-12-17 14:02:24 +01008013 /* the function for the accept() event */
8014 fdtab[fd].read = &event_accept;
8015 fdtab[fd].write = NULL; /* never called */
8016 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
8017 curproxy->state = PR_STRUN;
8018 fdtab[fd].state = FD_STLISTEN;
8019 FD_SET(fd, StaticReadEvent);
8020 fd_insert(fd);
8021 listeners++;
8022 }
willy tarreaua1598082005-12-17 13:08:06 +01008023 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01008024 }
8025 return 0;
8026}
8027
willy tarreaub952e1d2005-12-18 01:31:20 +01008028int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008029
8030 appsess *temp1,*temp2;
8031 temp1 = (appsess *)key1;
8032 temp2 = (appsess *)key2;
8033
8034 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8035 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8036
8037 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8038}/* end match_str */
8039
willy tarreaub952e1d2005-12-18 01:31:20 +01008040void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008041 appsess *temp1;
8042
8043 //printf("destroy called\n");
8044 temp1 = (appsess *)data;
8045
8046 if (temp1->sessid)
8047 pool_free_to(apools.sessid, temp1->sessid);
8048
8049 if (temp1->serverid)
8050 pool_free_to(apools.serverid, temp1->serverid);
8051
8052 pool_free(appsess, temp1);
8053} /* end destroy */
8054
8055void appsession_cleanup( void )
8056{
8057 struct proxy *p = proxy;
8058
8059 while(p) {
8060 chtbl_destroy(&(p->htbl_proxy));
8061 p = p->next;
8062 }
8063}/* end appsession_cleanup() */
8064
8065void pool_destroy(void **pool)
8066{
8067 void *temp, *next;
8068 next = pool;
8069 while (next) {
8070 temp = next;
8071 next = *(void **)temp;
8072 free(temp);
8073 }
8074}/* end pool_destroy() */
8075
willy tarreaub952e1d2005-12-18 01:31:20 +01008076void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008077 struct proxy *p = proxy;
8078 struct cap_hdr *h,*h_next;
8079 struct server *s,*s_next;
8080 struct listener *l,*l_next;
8081
8082 while (p) {
8083 if (p->id)
8084 free(p->id);
8085
8086 if (p->check_req)
8087 free(p->check_req);
8088
8089 if (p->cookie_name)
8090 free(p->cookie_name);
8091
8092 if (p->capture_name)
8093 free(p->capture_name);
8094
8095 /* only strup if the user have set in config.
8096 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008097 if (p->errmsg.msg400) free(p->errmsg.msg400);
8098 if (p->errmsg.msg403) free(p->errmsg.msg403);
8099 if (p->errmsg.msg408) free(p->errmsg.msg408);
8100 if (p->errmsg.msg500) free(p->errmsg.msg500);
8101 if (p->errmsg.msg502) free(p->errmsg.msg502);
8102 if (p->errmsg.msg503) free(p->errmsg.msg503);
8103 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008104 */
8105 if (p->appsession_name)
8106 free(p->appsession_name);
8107
8108 h = p->req_cap;
8109 while (h) {
8110 h_next = h->next;
8111 if (h->name)
8112 free(h->name);
8113 pool_destroy(h->pool);
8114 free(h);
8115 h = h_next;
8116 }/* end while(h) */
8117
8118 h = p->rsp_cap;
8119 while (h) {
8120 h_next = h->next;
8121 if (h->name)
8122 free(h->name);
8123
8124 pool_destroy(h->pool);
8125 free(h);
8126 h = h_next;
8127 }/* end while(h) */
8128
8129 s = p->srv;
8130 while (s) {
8131 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008132 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008133 free(s->id);
8134
willy tarreaub952e1d2005-12-18 01:31:20 +01008135 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008136 free(s->cookie);
8137
8138 free(s);
8139 s = s_next;
8140 }/* end while(s) */
8141
8142 l = p->listen;
8143 while (l) {
8144 l_next = l->next;
8145 free(l);
8146 l = l_next;
8147 }/* end while(l) */
8148
8149 pool_destroy((void **) p->req_cap_pool);
8150 pool_destroy((void **) p->rsp_cap_pool);
8151 p = p->next;
8152 }/* end while(p) */
8153
8154 if (global.chroot) free(global.chroot);
8155 if (global.pidfile) free(global.pidfile);
8156
willy tarreau12350152005-12-18 01:03:27 +01008157 if (StaticReadEvent) free(StaticReadEvent);
8158 if (StaticWriteEvent) free(StaticWriteEvent);
8159 if (fdtab) free(fdtab);
8160
8161 pool_destroy(pool_session);
8162 pool_destroy(pool_buffer);
8163 pool_destroy(pool_fdtab);
8164 pool_destroy(pool_requri);
8165 pool_destroy(pool_task);
8166 pool_destroy(pool_capture);
8167 pool_destroy(pool_appsess);
8168
8169 if (have_appsession) {
8170 pool_destroy(apools.serverid);
8171 pool_destroy(apools.sessid);
8172 }
8173} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008174
8175int main(int argc, char **argv) {
willy tarreaub1285d52005-12-18 01:20:14 +01008176 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008177 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008178 init(argc, argv);
8179
willy tarreau0f7af912005-12-17 12:21:26 +01008180 signal(SIGQUIT, dump);
8181 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008182 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008183#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008184 signal(SIGINT, sig_int);
8185 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008186#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008187
8188 /* on very high loads, a sigpipe sometimes happen just between the
8189 * getsockopt() which tells "it's OK to write", and the following write :-(
8190 */
willy tarreau3242e862005-12-17 12:27:53 +01008191#ifndef MSG_NOSIGNAL
8192 signal(SIGPIPE, SIG_IGN);
8193#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008194
willy tarreaud0fb4652005-12-18 01:32:04 +01008195 /* start_proxies() sends an alert when it fails. */
willy tarreau0f7af912005-12-17 12:21:26 +01008196 if (start_proxies() < 0)
8197 exit(1);
willy tarreaud0fb4652005-12-18 01:32:04 +01008198
8199 if (listeners == 0) {
8200 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
8201 exit(1);
8202 }
8203
willy tarreaudbd3bef2006-01-20 19:35:18 +01008204 /* prepare pause/play signals */
8205 signal(SIGTTOU, sig_pause);
8206 signal(SIGTTIN, sig_listen);
8207
Willy TARREAUe3283d12006-03-01 22:15:29 +01008208 if (global.mode & MODE_DAEMON) {
8209 global.mode &= ~MODE_VERBOSE;
8210 global.mode |= MODE_QUIET;
8211 }
8212
willy tarreaud0fb4652005-12-18 01:32:04 +01008213 /* MODE_QUIET can inhibit alerts and warnings below this line */
8214
8215 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008216 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008217 /* detach from the tty */
8218 fclose(stdin); fclose(stdout); fclose(stderr);
8219 close(0); close(1); close(2);
8220 }
willy tarreau0f7af912005-12-17 12:21:26 +01008221
willy tarreaufe2c5c12005-12-17 14:14:34 +01008222 /* open log & pid files before the chroot */
8223 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8224 int pidfd;
8225 unlink(global.pidfile);
8226 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8227 if (pidfd < 0) {
8228 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
8229 exit(1);
8230 }
8231 pidfile = fdopen(pidfd, "w");
8232 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008233
8234 /* chroot if needed */
8235 if (global.chroot != NULL) {
8236 if (chroot(global.chroot) == -1) {
8237 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
8238 exit(1);
8239 }
8240 chdir("/");
8241 }
8242
willy tarreaub1285d52005-12-18 01:20:14 +01008243 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01008244 if (!global.rlimit_nofile)
8245 global.rlimit_nofile = global.maxsock;
8246
willy tarreaub1285d52005-12-18 01:20:14 +01008247 if (global.rlimit_nofile) {
8248 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8249 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8250 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8251 }
8252 }
8253
willy tarreau9fe663a2005-12-17 13:02:59 +01008254 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008255 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008256 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8257 exit(1);
8258 }
8259
willy tarreau036e1ce2005-12-17 13:46:33 +01008260 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008261 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8262 exit(1);
8263 }
8264
willy tarreaub1285d52005-12-18 01:20:14 +01008265 /* check ulimits */
8266 limit.rlim_cur = limit.rlim_max = 0;
8267 getrlimit(RLIMIT_NOFILE, &limit);
8268 if (limit.rlim_cur < global.maxsock) {
8269 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",
8270 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8271 }
8272
willy tarreau9fe663a2005-12-17 13:02:59 +01008273 if (global.mode & MODE_DAEMON) {
8274 int ret = 0;
8275 int proc;
8276
8277 /* the father launches the required number of processes */
8278 for (proc = 0; proc < global.nbproc; proc++) {
8279 ret = fork();
8280 if (ret < 0) {
8281 Alert("[%s.main()] Cannot fork.\n", argv[0]);
8282 exit(1); /* there has been an error */
8283 }
8284 else if (ret == 0) /* child breaks here */
8285 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008286 if (pidfile != NULL) {
8287 fprintf(pidfile, "%d\n", ret);
8288 fflush(pidfile);
8289 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008290 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008291 /* close the pidfile both in children and father */
8292 if (pidfile != NULL)
8293 fclose(pidfile);
8294 free(global.pidfile);
8295
willy tarreau9fe663a2005-12-17 13:02:59 +01008296 if (proc == global.nbproc)
8297 exit(0); /* parent must leave */
8298
willy tarreau750a4722005-12-17 13:21:24 +01008299 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8300 * that we can detach from the TTY. We MUST NOT do it in other cases since
8301 * it would have already be done, and 0-2 would have been affected to listening
8302 * sockets
8303 */
8304 if (!(global.mode & MODE_QUIET)) {
8305 /* detach from the tty */
8306 fclose(stdin); fclose(stdout); fclose(stderr);
8307 close(0); close(1); close(2); /* close all fd's */
8308 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8309 }
willy tarreaua1598082005-12-17 13:08:06 +01008310 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008311 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008312 }
8313
willy tarreau1c2ad212005-12-18 01:11:29 +01008314#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008315 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008316 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8317 epoll_loop(POLL_LOOP_ACTION_RUN);
8318 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008319 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008320 }
8321 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008322 Warning("epoll() is not available. Using poll()/select() instead.\n");
8323 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008324 }
8325 }
8326#endif
8327
8328#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008329 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008330 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8331 poll_loop(POLL_LOOP_ACTION_RUN);
8332 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008333 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008334 }
8335 else {
8336 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008337 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008338 }
8339 }
8340#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008341 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008342 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8343 select_loop(POLL_LOOP_ACTION_RUN);
8344 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008345 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008346 }
8347 }
8348
willy tarreau0f7af912005-12-17 12:21:26 +01008349
willy tarreau12350152005-12-18 01:03:27 +01008350 /* Free all Hash Keys and all Hash elements */
8351 appsession_cleanup();
8352 /* Do some cleanup */
8353 deinit();
8354
willy tarreau0f7af912005-12-17 12:21:26 +01008355 exit(0);
8356}
willy tarreau12350152005-12-18 01:03:27 +01008357
8358#if defined(DEBUG_HASH)
8359static void print_table(const CHTbl *htbl) {
8360
8361 ListElmt *element;
8362 int i;
8363 appsess *asession;
8364
8365 /*****************************************************************************
8366 * *
8367 * Display the chained hash table. *
8368 * *
8369 *****************************************************************************/
8370
8371 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8372
8373 for (i = 0; i < TBLSIZ; i++) {
8374 fprintf(stdout, "Bucket[%03d]\n", i);
8375
8376 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8377 //fprintf(stdout, "%c", *(char *)list_data(element));
8378 asession = (appsess *)list_data(element);
8379 fprintf(stdout, "ELEM :%s:", asession->sessid);
8380 fprintf(stdout, " Server :%s: \n", asession->serverid);
8381 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8382 }
8383
8384 fprintf(stdout, "\n");
8385 }
8386 return;
8387} /* end print_table */
8388#endif
8389
8390static int appsession_init(void)
8391{
8392 static int initialized = 0;
8393 int idlen;
8394 struct server *s;
8395 struct proxy *p = proxy;
8396
8397 if (!initialized) {
8398 if (!appsession_task_init()) {
8399 apools.sessid = NULL;
8400 apools.serverid = NULL;
8401 apools.ser_waste = 0;
8402 apools.ser_use = 0;
8403 apools.ser_msize = sizeof(void *);
8404 apools.ses_waste = 0;
8405 apools.ses_use = 0;
8406 apools.ses_msize = sizeof(void *);
8407 while (p) {
8408 s = p->srv;
8409 if (apools.ses_msize < p->appsession_len)
8410 apools.ses_msize = p->appsession_len;
8411 while (s) {
8412 idlen = strlen(s->id);
8413 if (apools.ser_msize < idlen)
8414 apools.ser_msize = idlen;
8415 s = s->next;
8416 }
8417 p = p->next;
8418 }
8419 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8420 apools.ses_msize ++;
8421 }
8422 else {
8423 fprintf(stderr, "appsession_task_init failed\n");
8424 return -1;
8425 }
8426 initialized ++;
8427 }
8428 return 0;
8429}
8430
8431static int appsession_task_init(void)
8432{
8433 static int initialized = 0;
8434 struct task *t;
8435 if (!initialized) {
8436 if ((t = pool_alloc(task)) == NULL)
8437 return -1;
8438 t->next = t->prev = t->rqnext = NULL;
8439 t->wq = LIST_HEAD(wait_queue);
8440 t->state = TASK_IDLE;
8441 t->context = NULL;
8442 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8443 task_queue(t);
8444 t->process = appsession_refresh;
8445 initialized ++;
8446 }
8447 return 0;
8448}
8449
8450static int appsession_refresh(struct task *t) {
8451 struct proxy *p = proxy;
8452 CHTbl *htbl;
8453 ListElmt *element, *last;
8454 int i;
8455 appsess *asession;
8456 void *data;
8457
8458 while (p) {
8459 if (p->appsession_name != NULL) {
8460 htbl = &p->htbl_proxy;
8461 /* if we ever give up the use of TBLSIZ, we need to change this */
8462 for (i = 0; i < TBLSIZ; i++) {
8463 last = NULL;
8464 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8465 asession = (appsess *)list_data(element);
8466 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8467 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8468 int len;
8469 /*
8470 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8471 */
8472 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8473 asession->sessid, asession->serverid?asession->serverid:"(null)");
8474 write(1, trash, len);
8475 }
8476 /* delete the expired element from within the hash table */
8477 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8478 && (htbl->table[i].destroy != NULL)) {
8479 htbl->table[i].destroy(data);
8480 }
8481 if (last == NULL) {/* patient lost his head, get a new one */
8482 element = list_head(&htbl->table[i]);
8483 if (element == NULL) break; /* no heads left, go to next patient */
8484 }
8485 else
8486 element = last;
8487 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8488 else
8489 last = element;
8490 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8491 }
8492 }
8493 p = p->next;
8494 }
8495 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8496 return TBLCHKINT;
8497} /* end appsession_refresh */
8498