blob: bad84a0974b06a90a49d215d8ce62890aae07939 [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 tarreau50be0172006-03-15 19:41:19 +010090#define HAPROXY_VERSION "1.2.9"
91#define HAPROXY_DATE "2006/03/15"
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 tarreau0f7af912005-12-17 12:21:26 +01002558
willy tarreau5cbea6f2005-12-17 12:48:26 +01002559 while (p->nbconn < p->maxconn) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002560 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002561 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002562
willy tarreaub1285d52005-12-18 01:20:14 +01002563 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2564 switch (errno) {
2565 case EAGAIN:
2566 case EINTR:
2567 case ECONNABORTED:
2568 return 0; /* nothing more to accept */
2569 case ENFILE:
2570 send_log(p, LOG_EMERG,
2571 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2572 p->id, maxfd);
2573 return 0;
2574 case EMFILE:
2575 send_log(p, LOG_EMERG,
2576 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2577 p->id, maxfd);
2578 return 0;
2579 case ENOBUFS:
2580 case ENOMEM:
2581 send_log(p, LOG_EMERG,
2582 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2583 p->id, maxfd);
2584 return 0;
2585 default:
2586 return 0;
2587 }
2588 }
willy tarreau0f7af912005-12-17 12:21:26 +01002589
willy tarreau5cbea6f2005-12-17 12:48:26 +01002590 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2591 Alert("out of memory in event_accept().\n");
2592 FD_CLR(fd, StaticReadEvent);
2593 p->state = PR_STIDLE;
2594 close(cfd);
2595 return 0;
2596 }
willy tarreau0f7af912005-12-17 12:21:26 +01002597
willy tarreaub1285d52005-12-18 01:20:14 +01002598 /* if this session comes from a known monitoring system, we want to ignore
2599 * it as soon as possible, which means closing it immediately for TCP.
2600 */
2601 s->flags = 0;
2602 if (addr.ss_family == AF_INET &&
2603 p->mon_mask.s_addr &&
2604 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2605 if (p->mode == PR_MODE_TCP) {
2606 close(cfd);
2607 pool_free(session, s);
2608 continue;
2609 }
2610 s->flags |= SN_MONITOR;
2611 }
2612
willy tarreau5cbea6f2005-12-17 12:48:26 +01002613 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2614 Alert("out of memory in event_accept().\n");
2615 FD_CLR(fd, StaticReadEvent);
2616 p->state = PR_STIDLE;
2617 close(cfd);
2618 pool_free(session, s);
2619 return 0;
2620 }
willy tarreau0f7af912005-12-17 12:21:26 +01002621
willy tarreau5cbea6f2005-12-17 12:48:26 +01002622 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002623 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002624 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2625 close(cfd);
2626 pool_free(task, t);
2627 pool_free(session, s);
2628 return 0;
2629 }
willy tarreau0f7af912005-12-17 12:21:26 +01002630
willy tarreau5cbea6f2005-12-17 12:48:26 +01002631 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2632 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2633 (char *) &one, sizeof(one)) == -1)) {
2634 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2635 close(cfd);
2636 pool_free(task, t);
2637 pool_free(session, s);
2638 return 0;
2639 }
willy tarreau0f7af912005-12-17 12:21:26 +01002640
willy tarreaub952e1d2005-12-18 01:31:20 +01002641 if (p->options & PR_O_TCP_CLI_KA)
2642 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2643
willy tarreau9fe663a2005-12-17 13:02:59 +01002644 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2645 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2646 t->state = TASK_IDLE;
2647 t->process = process_session;
2648 t->context = s;
2649
2650 s->task = t;
2651 s->proxy = p;
2652 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2653 s->srv_state = SV_STIDLE;
2654 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002655
willy tarreau9fe663a2005-12-17 13:02:59 +01002656 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2657 s->cli_fd = cfd;
2658 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002659 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002660 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002661
willy tarreaub1285d52005-12-18 01:20:14 +01002662 if (s->flags & SN_MONITOR)
2663 s->logs.logwait = 0;
2664 else
2665 s->logs.logwait = p->to_log;
2666
willy tarreaua1598082005-12-17 13:08:06 +01002667 s->logs.tv_accept = now;
2668 s->logs.t_request = -1;
2669 s->logs.t_connect = -1;
2670 s->logs.t_data = -1;
2671 s->logs.t_close = 0;
2672 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002673 s->logs.cli_cookie = NULL;
2674 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002675 s->logs.status = -1;
2676 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002677
willy tarreau2f6ba652005-12-17 13:57:42 +01002678 s->uniq_id = totalconn;
2679
willy tarreau4302f492005-12-18 01:00:37 +01002680 if (p->nb_req_cap > 0) {
2681 if ((s->req_cap =
2682 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2683 == NULL) { /* no memory */
2684 close(cfd); /* nothing can be done for this fd without memory */
2685 pool_free(task, t);
2686 pool_free(session, s);
2687 return 0;
2688 }
2689 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2690 }
2691 else
2692 s->req_cap = NULL;
2693
2694 if (p->nb_rsp_cap > 0) {
2695 if ((s->rsp_cap =
2696 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2697 == NULL) { /* no memory */
2698 if (s->req_cap != NULL)
2699 pool_free_to(p->req_cap_pool, s->req_cap);
2700 close(cfd); /* nothing can be done for this fd without memory */
2701 pool_free(task, t);
2702 pool_free(session, s);
2703 return 0;
2704 }
2705 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2706 }
2707 else
2708 s->rsp_cap = NULL;
2709
willy tarreau5cbea6f2005-12-17 12:48:26 +01002710 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2711 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002712 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002713 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002714
willy tarreau8a86dbf2005-12-18 00:45:59 +01002715 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002716 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002717 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002718 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002719
willy tarreau9fe663a2005-12-17 13:02:59 +01002720 if (p->to_log) {
2721 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002722 if (s->logs.logwait & LW_CLIP)
2723 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002724 sess_log(s);
2725 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002726 else if (s->cli_addr.ss_family == AF_INET) {
2727 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2728 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2729 sn, sizeof(sn)) &&
2730 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2731 pn, sizeof(pn))) {
2732 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2733 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2734 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2735 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2736 }
2737 }
2738 else {
2739 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2740 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2741 sn, sizeof(sn)) &&
2742 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2743 pn, sizeof(pn))) {
2744 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2745 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2746 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2747 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2748 }
2749 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002750 }
willy tarreau0f7af912005-12-17 12:21:26 +01002751
willy tarreau982249e2005-12-18 00:57:06 +01002752 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002753 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002754 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002755 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002756 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002757 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002758 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002759 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002760
willy tarreau8a86dbf2005-12-18 00:45:59 +01002761 if (s->cli_addr.ss_family == AF_INET) {
2762 char pn[INET_ADDRSTRLEN];
2763 inet_ntop(AF_INET,
2764 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2765 pn, sizeof(pn));
2766
2767 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2768 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2769 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2770 }
2771 else {
2772 char pn[INET6_ADDRSTRLEN];
2773 inet_ntop(AF_INET6,
2774 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2775 pn, sizeof(pn));
2776
2777 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2778 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2779 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2780 }
2781
willy tarreauef900ab2005-12-17 12:52:52 +01002782 write(1, trash, len);
2783 }
willy tarreau0f7af912005-12-17 12:21:26 +01002784
willy tarreau5cbea6f2005-12-17 12:48:26 +01002785 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002786 if (s->rsp_cap != NULL)
2787 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2788 if (s->req_cap != NULL)
2789 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002790 close(cfd); /* nothing can be done for this fd without memory */
2791 pool_free(task, t);
2792 pool_free(session, s);
2793 return 0;
2794 }
willy tarreau4302f492005-12-18 01:00:37 +01002795
willy tarreau5cbea6f2005-12-17 12:48:26 +01002796 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002797 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002798 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2799 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002800 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002801 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002802
willy tarreau5cbea6f2005-12-17 12:48:26 +01002803 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2804 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002805 if (s->rsp_cap != NULL)
2806 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2807 if (s->req_cap != NULL)
2808 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002809 close(cfd); /* nothing can be done for this fd without memory */
2810 pool_free(task, t);
2811 pool_free(session, s);
2812 return 0;
2813 }
2814 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002815 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002816 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 +01002817
willy tarreau5cbea6f2005-12-17 12:48:26 +01002818 fdtab[cfd].read = &event_cli_read;
2819 fdtab[cfd].write = &event_cli_write;
2820 fdtab[cfd].owner = t;
2821 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002822
willy tarreaub1285d52005-12-18 01:20:14 +01002823 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2824 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2825 /* Either we got a request from a monitoring system on an HTTP instance,
2826 * or we're in health check mode with the 'httpchk' option enabled. In
2827 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2828 */
2829 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2830 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2831 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002832 }
2833 else {
2834 FD_SET(cfd, StaticReadEvent);
2835 }
2836
willy tarreaub952e1d2005-12-18 01:31:20 +01002837#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2838 if (PrevReadEvent) {
2839 assert(!(FD_ISSET(cfd, PrevReadEvent)));
2840 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
2841 }
2842#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002843 fd_insert(cfd);
2844
2845 tv_eternity(&s->cnexpire);
2846 tv_eternity(&s->srexpire);
2847 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01002848 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002849 tv_eternity(&s->cwexpire);
2850
willy tarreaub1285d52005-12-18 01:20:14 +01002851 if (s->proxy->clitimeout) {
2852 if (FD_ISSET(cfd, StaticReadEvent))
2853 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2854 if (FD_ISSET(cfd, StaticWriteEvent))
2855 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
2856 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002857
willy tarreaub1285d52005-12-18 01:20:14 +01002858 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002859
2860 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002861
2862 if (p->mode != PR_MODE_HEALTH)
2863 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002864
2865 p->nbconn++;
2866 actconn++;
2867 totalconn++;
2868
willy tarreaub952e1d2005-12-18 01:31:20 +01002869 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002870 } /* end of while (p->nbconn < p->maxconn) */
2871 return 0;
2872}
willy tarreau0f7af912005-12-17 12:21:26 +01002873
willy tarreau0f7af912005-12-17 12:21:26 +01002874
willy tarreau5cbea6f2005-12-17 12:48:26 +01002875/*
2876 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002877 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2878 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002879 * or -1 if an error occured.
2880 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002881int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002882 struct task *t = fdtab[fd].owner;
2883 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002884 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01002885 socklen_t lskerr = sizeof(skerr);
2886
willy tarreau05be12b2006-03-19 19:35:00 +01002887 skerr = 1;
2888 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
2889 || (skerr != 0)) {
2890 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002891 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01002892 fdtab[fd].state = FD_STERROR;
2893 FD_CLR(fd, StaticWriteEvent);
2894 }
willy tarreaua4a583a2005-12-18 01:39:19 +01002895 else if (s->result != -1) {
2896 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002897 if (s->proxy->options & PR_O_HTTP_CHK) {
2898 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002899 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002900 * so we'll send the request, and won't wake the checker up now.
2901 */
2902#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002903 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002904#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002905 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002906#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002907 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002908 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2909 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2910 return 0;
2911 }
willy tarreau05be12b2006-03-19 19:35:00 +01002912 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002913 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01002914 FD_CLR(fd, StaticWriteEvent);
2915 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002916 }
2917 else {
2918 /* good TCP connection is enough */
2919 s->result = 1;
2920 }
2921 }
2922
2923 task_wakeup(&rq, t);
2924 return 0;
2925}
2926
willy tarreau0f7af912005-12-17 12:21:26 +01002927
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002928/*
2929 * This function is used only for server health-checks. It handles
2930 * the server's reply to an HTTP request. It returns 1 if the server replies
2931 * 2xx or 3xx (valid responses), or -1 in other cases.
2932 */
2933int event_srv_chk_r(int fd) {
2934 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01002935 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002936 struct task *t = fdtab[fd].owner;
2937 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01002938 int skerr;
2939 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002940
willy tarreaua4a583a2005-12-18 01:39:19 +01002941 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002942
willy tarreau05be12b2006-03-19 19:35:00 +01002943 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2944 if (!skerr) {
2945#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002946 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002947#else
willy tarreau05be12b2006-03-19 19:35:00 +01002948 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2949 * but the connection was closed on the remote end. Fortunately, recv still
2950 * works correctly and we don't need to do the getsockopt() on linux.
2951 */
2952 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002953#endif
willy tarreau05be12b2006-03-19 19:35:00 +01002954
2955 if ((len >= sizeof("HTTP/1.0 000")) &&
2956 !memcmp(reply, "HTTP/1.", 7) &&
2957 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2958 result = 1;
2959 }
2960
2961 if (result == -1)
2962 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01002963
2964 if (s->result != -1)
2965 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002966
2967 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002968 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002969 return 0;
2970}
2971
2972
2973/*
2974 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2975 * and moves <end> just after the end of <str>.
2976 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2977 * the shift value (positive or negative) is returned.
2978 * If there's no space left, the move is not done.
2979 *
2980 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002981int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002982 int delta;
2983 int len;
2984
2985 len = strlen(str);
2986 delta = len - (end - pos);
2987
2988 if (delta + b->r >= b->data + BUFSIZE)
2989 return 0; /* no space left */
2990
2991 /* first, protect the end of the buffer */
2992 memmove(end + delta, end, b->data + b->l - end);
2993
2994 /* now, copy str over pos */
2995 memcpy(pos, str,len);
2996
willy tarreau5cbea6f2005-12-17 12:48:26 +01002997 /* we only move data after the displaced zone */
2998 if (b->r > pos) b->r += delta;
2999 if (b->w > pos) b->w += delta;
3000 if (b->h > pos) b->h += delta;
3001 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003002 b->l += delta;
3003
3004 return delta;
3005}
3006
willy tarreau8337c6b2005-12-17 13:41:01 +01003007/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003008 * len is 0.
3009 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003010int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003011 int delta;
3012
3013 delta = len - (end - pos);
3014
3015 if (delta + b->r >= b->data + BUFSIZE)
3016 return 0; /* no space left */
3017
Willy TARREAUe78ae262006-01-08 01:24:12 +01003018 if (b->data + b->l < end)
3019 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3020 return 0;
3021
willy tarreau0f7af912005-12-17 12:21:26 +01003022 /* first, protect the end of the buffer */
3023 memmove(end + delta, end, b->data + b->l - end);
3024
3025 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003026 if (len)
3027 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003028
willy tarreau5cbea6f2005-12-17 12:48:26 +01003029 /* we only move data after the displaced zone */
3030 if (b->r > pos) b->r += delta;
3031 if (b->w > pos) b->w += delta;
3032 if (b->h > pos) b->h += delta;
3033 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003034 b->l += delta;
3035
3036 return delta;
3037}
3038
3039
3040int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3041 char *old_dst = dst;
3042
3043 while (*str) {
3044 if (*str == '\\') {
3045 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003046 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003047 int len, num;
3048
3049 num = *str - '0';
3050 str++;
3051
willy tarreau8a86dbf2005-12-18 00:45:59 +01003052 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003053 len = matches[num].rm_eo - matches[num].rm_so;
3054 memcpy(dst, src + matches[num].rm_so, len);
3055 dst += len;
3056 }
3057
3058 }
3059 else if (*str == 'x') {
3060 unsigned char hex1, hex2;
3061 str++;
3062
willy tarreauc1f47532005-12-18 01:08:26 +01003063 hex1 = toupper(*str++) - '0';
3064 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003065
3066 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3067 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3068 *dst++ = (hex1<<4) + hex2;
3069 }
3070 else
3071 *dst++ = *str++;
3072 }
3073 else
3074 *dst++ = *str++;
3075 }
3076 *dst = 0;
3077 return dst - old_dst;
3078}
3079
willy tarreauc1f47532005-12-18 01:08:26 +01003080static int ishex(char s)
3081{
3082 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3083}
3084
3085/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3086char *check_replace_string(char *str)
3087{
3088 char *err = NULL;
3089 while (*str) {
3090 if (*str == '\\') {
3091 err = str; /* in case of a backslash, we return the pointer to it */
3092 str++;
3093 if (!*str)
3094 return err;
3095 else if (isdigit((int)*str))
3096 err = NULL;
3097 else if (*str == 'x') {
3098 str++;
3099 if (!ishex(*str))
3100 return err;
3101 str++;
3102 if (!ishex(*str))
3103 return err;
3104 err = NULL;
3105 }
3106 else {
3107 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3108 err = NULL;
3109 }
3110 }
3111 str++;
3112 }
3113 return err;
3114}
3115
3116
willy tarreau9fe663a2005-12-17 13:02:59 +01003117
willy tarreau0f7af912005-12-17 12:21:26 +01003118/*
3119 * manages the client FSM and its socket. BTW, it also tries to handle the
3120 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3121 * 0 else.
3122 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003123int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003124 int s = t->srv_state;
3125 int c = t->cli_state;
3126 struct buffer *req = t->req;
3127 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003128 int method_checked = 0;
3129 appsess *asession_temp = NULL;
3130 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003131
willy tarreau750a4722005-12-17 13:21:24 +01003132#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003133 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3134 cli_stnames[c], srv_stnames[s],
3135 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3136 t->crexpire.tv_sec, t->crexpire.tv_usec,
3137 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003138#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003139 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3140 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3141 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3142 //);
3143 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003144 /* now parse the partial (or complete) headers */
3145 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3146 char *ptr;
3147 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003148 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003149
willy tarreau5cbea6f2005-12-17 12:48:26 +01003150 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003151
willy tarreau0f7af912005-12-17 12:21:26 +01003152 /* look for the end of the current header */
3153 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3154 ptr++;
3155
willy tarreau5cbea6f2005-12-17 12:48:26 +01003156 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003157 int line, len;
3158 /* we can only get here after an end of headers */
3159 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003160
willy tarreaue39cd132005-12-17 13:00:18 +01003161 if (t->flags & SN_CLDENY) {
3162 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003163 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003164 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003165 if (!(t->flags & SN_ERR_MASK))
3166 t->flags |= SN_ERR_PRXCOND;
3167 if (!(t->flags & SN_FINST_MASK))
3168 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003169 return 1;
3170 }
3171
willy tarreau5cbea6f2005-12-17 12:48:26 +01003172 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003173 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3174 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003175 }
willy tarreau0f7af912005-12-17 12:21:26 +01003176
willy tarreau9fe663a2005-12-17 13:02:59 +01003177 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003178 if (t->cli_addr.ss_family == AF_INET) {
3179 unsigned char *pn;
3180 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3181 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3182 pn[0], pn[1], pn[2], pn[3]);
3183 buffer_replace2(req, req->h, req->h, trash, len);
3184 }
3185 else if (t->cli_addr.ss_family == AF_INET6) {
3186 char pn[INET6_ADDRSTRLEN];
3187 inet_ntop(AF_INET6,
3188 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3189 pn, sizeof(pn));
3190 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3191 buffer_replace2(req, req->h, req->h, trash, len);
3192 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003193 }
3194
willy tarreau25c4ea52005-12-18 00:49:49 +01003195 /* add a "connection: close" line if needed */
3196 if (t->proxy->options & PR_O_HTTP_CLOSE)
3197 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3198
willy tarreau982249e2005-12-18 00:57:06 +01003199 if (!memcmp(req->data, "POST ", 5)) {
3200 /* this is a POST request, which is not cacheable by default */
3201 t->flags |= SN_POST;
3202 }
willy tarreaucd878942005-12-17 13:27:43 +01003203
willy tarreau5cbea6f2005-12-17 12:48:26 +01003204 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003205 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003206
willy tarreau750a4722005-12-17 13:21:24 +01003207 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003208 /* FIXME: we'll set the client in a wait state while we try to
3209 * connect to the server. Is this really needed ? wouldn't it be
3210 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003211 //FD_CLR(t->cli_fd, StaticReadEvent);
3212 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003213
3214 /* FIXME: if we break here (as up to 1.1.23), having the client
3215 * shutdown its connection can lead to an abort further.
3216 * it's better to either return 1 or even jump directly to the
3217 * data state which will save one schedule.
3218 */
3219 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003220
3221 if (!t->proxy->clitimeout ||
3222 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3223 /* If the client has no timeout, or if the server is not ready yet,
3224 * and we know for sure that it can expire, then it's cleaner to
3225 * disable the timeout on the client side so that too low values
3226 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003227 *
3228 * FIXME-20050705: the server needs a way to re-enable this time-out
3229 * when it switches its state, otherwise a client can stay connected
3230 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003231 */
3232 tv_eternity(&t->crexpire);
3233
willy tarreau197e8ec2005-12-17 14:10:59 +01003234 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003235 }
willy tarreau0f7af912005-12-17 12:21:26 +01003236
Willy TARREAU13032e72006-03-12 17:31:45 +01003237 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3238 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003239 /* this is a partial header, let's wait for more to come */
3240 req->lr = ptr;
3241 break;
3242 }
willy tarreau0f7af912005-12-17 12:21:26 +01003243
willy tarreau5cbea6f2005-12-17 12:48:26 +01003244 /* now we know that *ptr is either \r or \n,
3245 * and that there are at least 1 char after it.
3246 */
3247 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3248 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3249 else
3250 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003251
willy tarreau5cbea6f2005-12-17 12:48:26 +01003252 /*
3253 * now we know that we have a full header ; we can do whatever
3254 * we want with these pointers :
3255 * req->h = beginning of header
3256 * ptr = end of header (first \r or \n)
3257 * req->lr = beginning of next line (next rep->h)
3258 * req->r = end of data (not used at this stage)
3259 */
willy tarreau0f7af912005-12-17 12:21:26 +01003260
willy tarreau12350152005-12-18 01:03:27 +01003261 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3262 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3263 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3264
3265 /* skip ; */
3266 request_line++;
3267
3268 /* look if we have a jsessionid */
3269
3270 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3271
3272 /* skip jsessionid= */
3273 request_line += t->proxy->appsession_name_len + 1;
3274
3275 /* First try if we allready have an appsession */
3276 asession_temp = &local_asession;
3277
3278 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3279 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3280 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3281 return 0;
3282 }
3283
3284 /* Copy the sessionid */
3285 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3286 asession_temp->sessid[t->proxy->appsession_len] = 0;
3287 asession_temp->serverid = NULL;
3288
3289 /* only do insert, if lookup fails */
3290 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3291 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3292 Alert("Not enough memory process_cli():asession:calloc().\n");
3293 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3294 return 0;
3295 }
3296 asession_temp->sessid = local_asession.sessid;
3297 asession_temp->serverid = local_asession.serverid;
3298 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003299 } /* end if (chtbl_lookup()) */
3300 else {
willy tarreau12350152005-12-18 01:03:27 +01003301 /*free wasted memory;*/
3302 pool_free_to(apools.sessid, local_asession.sessid);
3303 }
3304
3305 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3306 asession_temp->request_count++;
3307
3308#if defined(DEBUG_HASH)
3309 print_table(&(t->proxy->htbl_proxy));
3310#endif
3311
3312 if (asession_temp->serverid == NULL) {
3313 Alert("Found Application Session without matching server.\n");
3314 } else {
3315 struct server *srv = t->proxy->srv;
3316 while (srv) {
3317 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3318 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3319 /* we found the server and it's usable */
3320 t->flags &= ~SN_CK_MASK;
3321 t->flags |= SN_CK_VALID | SN_DIRECT;
3322 t->srv = srv;
3323 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003324 } else {
willy tarreau12350152005-12-18 01:03:27 +01003325 t->flags &= ~SN_CK_MASK;
3326 t->flags |= SN_CK_DOWN;
3327 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003328 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003329 srv = srv->next;
3330 }/* end while(srv) */
3331 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003332 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003333 else {
3334 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3335 }
willy tarreau598da412005-12-18 01:07:29 +01003336 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003337 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003338 else{
3339 //printf("No Methode-Header with Session-String\n");
3340 }
3341
willy tarreau8337c6b2005-12-17 13:41:01 +01003342 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003343 /* we have a complete HTTP request that we must log */
3344 int urilen;
3345
willy tarreaua1598082005-12-17 13:08:06 +01003346 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003347 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003348 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003349 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003350 if (!(t->flags & SN_ERR_MASK))
3351 t->flags |= SN_ERR_PRXCOND;
3352 if (!(t->flags & SN_FINST_MASK))
3353 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003354 return 1;
3355 }
3356
3357 urilen = ptr - req->h;
3358 if (urilen >= REQURI_LEN)
3359 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003360 memcpy(t->logs.uri, req->h, urilen);
3361 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003362
willy tarreaua1598082005-12-17 13:08:06 +01003363 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003364 sess_log(t);
3365 }
willy tarreau4302f492005-12-18 01:00:37 +01003366 else if (t->logs.logwait & LW_REQHDR) {
3367 struct cap_hdr *h;
3368 int len;
3369 for (h = t->proxy->req_cap; h; h = h->next) {
3370 if ((h->namelen + 2 <= ptr - req->h) &&
3371 (req->h[h->namelen] == ':') &&
3372 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3373
3374 if (t->req_cap[h->index] == NULL)
3375 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3376
3377 len = ptr - (req->h + h->namelen + 2);
3378 if (len > h->len)
3379 len = h->len;
3380
3381 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3382 t->req_cap[h->index][len]=0;
3383 }
3384 }
3385
3386 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003387
willy tarreau5cbea6f2005-12-17 12:48:26 +01003388 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003389
willy tarreau982249e2005-12-18 00:57:06 +01003390 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003391 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003392 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 +01003393 max = ptr - req->h;
3394 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003395 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003396 trash[len++] = '\n';
3397 write(1, trash, len);
3398 }
willy tarreau0f7af912005-12-17 12:21:26 +01003399
willy tarreau25c4ea52005-12-18 00:49:49 +01003400
3401 /* remove "connection: " if needed */
3402 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3403 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3404 delete_header = 1;
3405 }
3406
willy tarreau5cbea6f2005-12-17 12:48:26 +01003407 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003408 if (!delete_header && t->proxy->req_exp != NULL
3409 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003410 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003411 char term;
3412
3413 term = *ptr;
3414 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003415 exp = t->proxy->req_exp;
3416 do {
3417 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3418 switch (exp->action) {
3419 case ACT_ALLOW:
3420 if (!(t->flags & SN_CLDENY))
3421 t->flags |= SN_CLALLOW;
3422 break;
3423 case ACT_REPLACE:
3424 if (!(t->flags & SN_CLDENY)) {
3425 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3426 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3427 }
3428 break;
3429 case ACT_REMOVE:
3430 if (!(t->flags & SN_CLDENY))
3431 delete_header = 1;
3432 break;
3433 case ACT_DENY:
3434 if (!(t->flags & SN_CLALLOW))
3435 t->flags |= SN_CLDENY;
3436 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003437 case ACT_PASS: /* we simply don't deny this one */
3438 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003439 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003440 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003441 }
willy tarreaue39cd132005-12-17 13:00:18 +01003442 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003443 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003444 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003445
willy tarreau240afa62005-12-17 13:14:35 +01003446 /* Now look for cookies. Conforming to RFC2109, we have to support
3447 * attributes whose name begin with a '$', and associate them with
3448 * the right cookie, if we want to delete this cookie.
3449 * So there are 3 cases for each cookie read :
3450 * 1) it's a special attribute, beginning with a '$' : ignore it.
3451 * 2) it's a server id cookie that we *MAY* want to delete : save
3452 * some pointers on it (last semi-colon, beginning of cookie...)
3453 * 3) it's an application cookie : we *MAY* have to delete a previous
3454 * "special" cookie.
3455 * At the end of loop, if a "special" cookie remains, we may have to
3456 * remove it. If no application cookie persists in the header, we
3457 * *MUST* delete it
3458 */
willy tarreau12350152005-12-18 01:03:27 +01003459 if (!delete_header &&
3460 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003461 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003462 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003463 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003464 char *del_colon, *del_cookie, *colon;
3465 int app_cookies;
3466
willy tarreau5cbea6f2005-12-17 12:48:26 +01003467 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003468 colon = p1;
3469 /* del_cookie == NULL => nothing to be deleted */
3470 del_colon = del_cookie = NULL;
3471 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003472
3473 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003474 /* skip spaces and colons, but keep an eye on these ones */
3475 while (p1 < ptr) {
3476 if (*p1 == ';' || *p1 == ',')
3477 colon = p1;
3478 else if (!isspace((int)*p1))
3479 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003480 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003481 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003482
3483 if (p1 == ptr)
3484 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003485
3486 /* p1 is at the beginning of the cookie name */
3487 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003488 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003489 p2++;
3490
3491 if (p2 == ptr)
3492 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003493
3494 p3 = p2 + 1; /* skips the '=' sign */
3495 if (p3 == ptr)
3496 break;
3497
willy tarreau240afa62005-12-17 13:14:35 +01003498 p4 = p3;
3499 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003500 p4++;
3501
3502 /* here, we have the cookie name between p1 and p2,
3503 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003504 * we can process it :
3505 *
3506 * Cookie: NAME=VALUE;
3507 * | || || |
3508 * | || || +--> p4
3509 * | || |+-------> p3
3510 * | || +--------> p2
3511 * | |+------------> p1
3512 * | +-------------> colon
3513 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003514 */
3515
willy tarreau240afa62005-12-17 13:14:35 +01003516 if (*p1 == '$') {
3517 /* skip this one */
3518 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003519 else {
3520 /* first, let's see if we want to capture it */
3521 if (t->proxy->capture_name != NULL &&
3522 t->logs.cli_cookie == NULL &&
3523 (p4 - p1 >= t->proxy->capture_namelen) &&
3524 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3525 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003526
willy tarreau8337c6b2005-12-17 13:41:01 +01003527 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3528 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003529 } else {
3530 if (log_len > t->proxy->capture_len)
3531 log_len = t->proxy->capture_len;
3532 memcpy(t->logs.cli_cookie, p1, log_len);
3533 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003534 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003535 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003536
3537 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3538 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3539 /* Cool... it's the right one */
3540 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003541 char *delim;
3542
3543 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3544 * have the server ID betweek p3 and delim, and the original cookie between
3545 * delim+1 and p4. Otherwise, delim==p4 :
3546 *
3547 * Cookie: NAME=SRV~VALUE;
3548 * | || || | |
3549 * | || || | +--> p4
3550 * | || || +--------> delim
3551 * | || |+-----------> p3
3552 * | || +------------> p2
3553 * | |+----------------> p1
3554 * | +-----------------> colon
3555 * +------------------------> req->h
3556 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003557
willy tarreau0174f312005-12-18 01:02:42 +01003558 if (t->proxy->options & PR_O_COOK_PFX) {
3559 for (delim = p3; delim < p4; delim++)
3560 if (*delim == COOKIE_DELIM)
3561 break;
3562 }
3563 else
3564 delim = p4;
3565
3566
3567 /* Here, we'll look for the first running server which supports the cookie.
3568 * This allows to share a same cookie between several servers, for example
3569 * to dedicate backup servers to specific servers only.
3570 */
3571 while (srv) {
3572 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3573 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3574 /* we found the server and it's usable */
3575 t->flags &= ~SN_CK_MASK;
3576 t->flags |= SN_CK_VALID | SN_DIRECT;
3577 t->srv = srv;
3578 break;
willy tarreau12350152005-12-18 01:03:27 +01003579 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003580 /* we found a server, but it's down */
3581 t->flags &= ~SN_CK_MASK;
3582 t->flags |= SN_CK_DOWN;
3583 }
3584 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003585 srv = srv->next;
3586 }
3587
willy tarreau0174f312005-12-18 01:02:42 +01003588 if (!srv && !(t->flags & SN_CK_DOWN)) {
3589 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003590 t->flags &= ~SN_CK_MASK;
3591 t->flags |= SN_CK_INVALID;
3592 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003593
willy tarreau0174f312005-12-18 01:02:42 +01003594 /* depending on the cookie mode, we may have to either :
3595 * - delete the complete cookie if we're in insert+indirect mode, so that
3596 * the server never sees it ;
3597 * - remove the server id from the cookie value, and tag the cookie as an
3598 * application cookie so that it does not get accidentely removed later,
3599 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003600 */
willy tarreau0174f312005-12-18 01:02:42 +01003601 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3602 buffer_replace2(req, p3, delim + 1, NULL, 0);
3603 p4 -= (delim + 1 - p3);
3604 ptr -= (delim + 1 - p3);
3605 del_cookie = del_colon = NULL;
3606 app_cookies++; /* protect the header from deletion */
3607 }
3608 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003609 (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 +01003610 del_cookie = p1;
3611 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003612 }
willy tarreau12350152005-12-18 01:03:27 +01003613 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003614 /* now we know that we must keep this cookie since it's
3615 * not ours. But if we wanted to delete our cookie
3616 * earlier, we cannot remove the complete header, but we
3617 * can remove the previous block itself.
3618 */
3619 app_cookies++;
3620
3621 if (del_cookie != NULL) {
3622 buffer_replace2(req, del_cookie, p1, NULL, 0);
3623 p4 -= (p1 - del_cookie);
3624 ptr -= (p1 - del_cookie);
3625 del_cookie = del_colon = NULL;
3626 }
willy tarreau240afa62005-12-17 13:14:35 +01003627 }
willy tarreau12350152005-12-18 01:03:27 +01003628
3629 if ((t->proxy->appsession_name != NULL) &&
3630 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3631 /* first, let's see if the cookie is our appcookie*/
3632
3633 /* Cool... it's the right one */
3634
3635 asession_temp = &local_asession;
3636
3637 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3638 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3639 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3640 return 0;
3641 }
3642
3643 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3644 asession_temp->sessid[t->proxy->appsession_len] = 0;
3645 asession_temp->serverid = NULL;
3646
3647 /* only do insert, if lookup fails */
3648 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3649 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3650 Alert("Not enough memory process_cli():asession:calloc().\n");
3651 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3652 return 0;
3653 }
3654
3655 asession_temp->sessid = local_asession.sessid;
3656 asession_temp->serverid = local_asession.serverid;
3657 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3658 }
3659 else{
3660 /* free wasted memory */
3661 pool_free_to(apools.sessid, local_asession.sessid);
3662 }
3663
3664 if (asession_temp->serverid == NULL) {
3665 Alert("Found Application Session without matching server.\n");
3666 } else {
3667 struct server *srv = t->proxy->srv;
3668 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003669 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003670 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3671 /* we found the server and it's usable */
3672 t->flags &= ~SN_CK_MASK;
3673 t->flags |= SN_CK_VALID | SN_DIRECT;
3674 t->srv = srv;
3675 break;
3676 } else {
3677 t->flags &= ~SN_CK_MASK;
3678 t->flags |= SN_CK_DOWN;
3679 }
3680 }
3681 srv = srv->next;
3682 }/* end while(srv) */
3683 }/* end else if server == NULL */
3684
3685 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003686 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003687 }
willy tarreau240afa62005-12-17 13:14:35 +01003688
willy tarreau5cbea6f2005-12-17 12:48:26 +01003689 /* we'll have to look for another cookie ... */
3690 p1 = p4;
3691 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003692
3693 /* There's no more cookie on this line.
3694 * We may have marked the last one(s) for deletion.
3695 * We must do this now in two ways :
3696 * - if there is no app cookie, we simply delete the header ;
3697 * - if there are app cookies, we must delete the end of the
3698 * string properly, including the colon/semi-colon before
3699 * the cookie name.
3700 */
3701 if (del_cookie != NULL) {
3702 if (app_cookies) {
3703 buffer_replace2(req, del_colon, ptr, NULL, 0);
3704 /* WARNING! <ptr> becomes invalid for now. If some code
3705 * below needs to rely on it before the end of the global
3706 * header loop, we need to correct it with this code :
3707 * ptr = del_colon;
3708 */
3709 }
3710 else
3711 delete_header = 1;
3712 }
3713 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003714
3715 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003716 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003717 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003718 }
willy tarreau240afa62005-12-17 13:14:35 +01003719 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3720
willy tarreau5cbea6f2005-12-17 12:48:26 +01003721 req->h = req->lr;
3722 } /* while (req->lr < req->r) */
3723
3724 /* end of header processing (even if incomplete) */
3725
willy tarreauef900ab2005-12-17 12:52:52 +01003726 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3727 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3728 * full. We cannot loop here since event_cli_read will disable it only if
3729 * req->l == rlim-data
3730 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003731 FD_SET(t->cli_fd, StaticReadEvent);
3732 if (t->proxy->clitimeout)
3733 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3734 else
3735 tv_eternity(&t->crexpire);
3736 }
3737
willy tarreaue39cd132005-12-17 13:00:18 +01003738 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003739 * won't be able to free more later, so the session will never terminate.
3740 */
willy tarreaue39cd132005-12-17 13:00:18 +01003741 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003742 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003743 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003744 if (!(t->flags & SN_ERR_MASK))
3745 t->flags |= SN_ERR_PRXCOND;
3746 if (!(t->flags & SN_FINST_MASK))
3747 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003748 return 1;
3749 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003750 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003751 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003752 tv_eternity(&t->crexpire);
3753 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003754 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003755 if (!(t->flags & SN_ERR_MASK))
3756 t->flags |= SN_ERR_CLICL;
3757 if (!(t->flags & SN_FINST_MASK))
3758 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003759 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003760 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003761 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3762
3763 /* read timeout : give up with an error message.
3764 */
3765 t->logs.status = 408;
3766 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003767 if (!(t->flags & SN_ERR_MASK))
3768 t->flags |= SN_ERR_CLITO;
3769 if (!(t->flags & SN_FINST_MASK))
3770 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003771 return 1;
3772 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003773
3774 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003775 }
3776 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003777 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003778 /* FIXME: this error handling is partly buggy because we always report
3779 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3780 * or HEADER phase. BTW, it's not logical to expire the client while
3781 * we're waiting for the server to connect.
3782 */
willy tarreau0f7af912005-12-17 12:21:26 +01003783 /* read or write error */
3784 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003785 tv_eternity(&t->crexpire);
3786 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003787 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003788 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003789 if (!(t->flags & SN_ERR_MASK))
3790 t->flags |= SN_ERR_CLICL;
3791 if (!(t->flags & SN_FINST_MASK))
3792 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003793 return 1;
3794 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003795 /* last read, or end of server write */
3796 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003797 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003798 tv_eternity(&t->crexpire);
3799 shutdown(t->cli_fd, SHUT_RD);
3800 t->cli_state = CL_STSHUTR;
3801 return 1;
3802 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003803 /* last server read and buffer empty */
3804 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003805 FD_CLR(t->cli_fd, StaticWriteEvent);
3806 tv_eternity(&t->cwexpire);
3807 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003808 /* We must ensure that the read part is still alive when switching
3809 * to shutw */
3810 FD_SET(t->cli_fd, StaticReadEvent);
3811 if (t->proxy->clitimeout)
3812 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003813 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003814 //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 +01003815 return 1;
3816 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003817 /* read timeout */
3818 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3819 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003820 tv_eternity(&t->crexpire);
3821 shutdown(t->cli_fd, SHUT_RD);
3822 t->cli_state = CL_STSHUTR;
3823 if (!(t->flags & SN_ERR_MASK))
3824 t->flags |= SN_ERR_CLITO;
3825 if (!(t->flags & SN_FINST_MASK))
3826 t->flags |= SN_FINST_D;
3827 return 1;
3828 }
3829 /* write timeout */
3830 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3831 FD_CLR(t->cli_fd, StaticWriteEvent);
3832 tv_eternity(&t->cwexpire);
3833 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003834 /* We must ensure that the read part is still alive when switching
3835 * to shutw */
3836 FD_SET(t->cli_fd, StaticReadEvent);
3837 if (t->proxy->clitimeout)
3838 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3839
willy tarreau036e1ce2005-12-17 13:46:33 +01003840 t->cli_state = CL_STSHUTW;
3841 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003842 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003843 if (!(t->flags & SN_FINST_MASK))
3844 t->flags |= SN_FINST_D;
3845 return 1;
3846 }
willy tarreau0f7af912005-12-17 12:21:26 +01003847
willy tarreauc58fc692005-12-17 14:13:08 +01003848 if (req->l >= req->rlim - req->data) {
3849 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003850 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003851 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003852 FD_CLR(t->cli_fd, StaticReadEvent);
3853 tv_eternity(&t->crexpire);
3854 }
3855 }
3856 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003857 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003858 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3859 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003860 if (!t->proxy->clitimeout ||
3861 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3862 /* If the client has no timeout, or if the server not ready yet, and we
3863 * know for sure that it can expire, then it's cleaner to disable the
3864 * timeout on the client side so that too low values cannot make the
3865 * sessions abort too early.
3866 */
willy tarreau0f7af912005-12-17 12:21:26 +01003867 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003868 else
3869 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003870 }
3871 }
3872
3873 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003874 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003875 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3876 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3877 tv_eternity(&t->cwexpire);
3878 }
3879 }
3880 else { /* buffer not empty */
3881 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3882 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003883 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003884 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003885 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3886 t->crexpire = t->cwexpire;
3887 }
willy tarreau0f7af912005-12-17 12:21:26 +01003888 else
3889 tv_eternity(&t->cwexpire);
3890 }
3891 }
3892 return 0; /* other cases change nothing */
3893 }
3894 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003895 if (t->res_cw == RES_ERROR) {
3896 tv_eternity(&t->cwexpire);
3897 fd_delete(t->cli_fd);
3898 t->cli_state = CL_STCLOSE;
3899 if (!(t->flags & SN_ERR_MASK))
3900 t->flags |= SN_ERR_CLICL;
3901 if (!(t->flags & SN_FINST_MASK))
3902 t->flags |= SN_FINST_D;
3903 return 1;
3904 }
3905 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003906 tv_eternity(&t->cwexpire);
3907 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003908 t->cli_state = CL_STCLOSE;
3909 return 1;
3910 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003911 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3912 tv_eternity(&t->cwexpire);
3913 fd_delete(t->cli_fd);
3914 t->cli_state = CL_STCLOSE;
3915 if (!(t->flags & SN_ERR_MASK))
3916 t->flags |= SN_ERR_CLITO;
3917 if (!(t->flags & SN_FINST_MASK))
3918 t->flags |= SN_FINST_D;
3919 return 1;
3920 }
willy tarreau0f7af912005-12-17 12:21:26 +01003921 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003922 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003923 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3924 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3925 tv_eternity(&t->cwexpire);
3926 }
3927 }
3928 else { /* buffer not empty */
3929 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3930 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003931 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003932 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003933 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3934 t->crexpire = t->cwexpire;
3935 }
willy tarreau0f7af912005-12-17 12:21:26 +01003936 else
3937 tv_eternity(&t->cwexpire);
3938 }
3939 }
3940 return 0;
3941 }
3942 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003943 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003944 tv_eternity(&t->crexpire);
3945 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003946 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003947 if (!(t->flags & SN_ERR_MASK))
3948 t->flags |= SN_ERR_CLICL;
3949 if (!(t->flags & SN_FINST_MASK))
3950 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003951 return 1;
3952 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003953 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3954 tv_eternity(&t->crexpire);
3955 fd_delete(t->cli_fd);
3956 t->cli_state = CL_STCLOSE;
3957 return 1;
3958 }
3959 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3960 tv_eternity(&t->crexpire);
3961 fd_delete(t->cli_fd);
3962 t->cli_state = CL_STCLOSE;
3963 if (!(t->flags & SN_ERR_MASK))
3964 t->flags |= SN_ERR_CLITO;
3965 if (!(t->flags & SN_FINST_MASK))
3966 t->flags |= SN_FINST_D;
3967 return 1;
3968 }
willy tarreauef900ab2005-12-17 12:52:52 +01003969 else if (req->l >= req->rlim - req->data) {
3970 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01003971
3972 /* FIXME-20050705: is it possible for a client to maintain a session
3973 * after the timeout by sending more data after it receives a close ?
3974 */
3975
willy tarreau0f7af912005-12-17 12:21:26 +01003976 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003977 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003978 FD_CLR(t->cli_fd, StaticReadEvent);
3979 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003980 //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 +01003981 }
3982 }
3983 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003984 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003985 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3986 FD_SET(t->cli_fd, StaticReadEvent);
3987 if (t->proxy->clitimeout)
3988 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3989 else
3990 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003991 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01003992 }
3993 }
3994 return 0;
3995 }
3996 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01003997 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01003998 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003999 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 +01004000 write(1, trash, len);
4001 }
4002 return 0;
4003 }
4004 return 0;
4005}
4006
4007
4008/*
4009 * manages the server FSM and its socket. It returns 1 if a state has changed
4010 * (and a resync may be needed), 0 else.
4011 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004012int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004013 int s = t->srv_state;
4014 int c = t->cli_state;
4015 struct buffer *req = t->req;
4016 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004017 appsess *asession_temp = NULL;
4018 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004019 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004020
willy tarreau750a4722005-12-17 13:21:24 +01004021#ifdef DEBUG_FULL
4022 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4023#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004024 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4025 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4026 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4027 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004028 if (s == SV_STIDLE) {
4029 if (c == CL_STHEADERS)
4030 return 0; /* stay in idle, waiting for data to reach the client side */
4031 else if (c == CL_STCLOSE ||
4032 c == CL_STSHUTW ||
4033 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4034 tv_eternity(&t->cnexpire);
4035 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004036 if (!(t->flags & SN_ERR_MASK))
4037 t->flags |= SN_ERR_CLICL;
4038 if (!(t->flags & SN_FINST_MASK))
4039 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004040 return 1;
4041 }
4042 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01004043 /* initiate a connection to the server */
4044 conn_err = connect_server(t);
4045 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004046 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4047 t->srv_state = SV_STCONN;
4048 }
4049 else { /* try again */
4050 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004051 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004052 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004053 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004054 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4055 t->flags &= ~SN_CK_MASK;
4056 t->flags |= SN_CK_DOWN;
4057 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004058 }
4059
willy tarreaub1285d52005-12-18 01:20:14 +01004060 conn_err = connect_server(t);
4061 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004062 t->srv_state = SV_STCONN;
4063 break;
4064 }
4065 }
4066 if (t->conn_retries < 0) {
4067 /* if conn_retries < 0 or other error, let's abort */
4068 tv_eternity(&t->cnexpire);
4069 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004070 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004071 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004072 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004073 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004074 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004075 if (!(t->flags & SN_FINST_MASK))
4076 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004077 }
4078 }
4079 return 1;
4080 }
4081 }
4082 else if (s == SV_STCONN) { /* connection in progress */
4083 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004084 //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 +01004085 return 0; /* nothing changed */
4086 }
4087 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4088 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4089 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004090 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004091 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004092 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004093 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004094 if (t->conn_retries >= 0) {
4095 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004096 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004097 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004098 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4099 t->flags &= ~SN_CK_MASK;
4100 t->flags |= SN_CK_DOWN;
4101 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004102 }
willy tarreaub1285d52005-12-18 01:20:14 +01004103 conn_err = connect_server(t);
4104 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004105 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004106 }
willy tarreaub1285d52005-12-18 01:20:14 +01004107 else if (t->res_sw == RES_SILENT)
4108 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4109 else
4110 conn_err = SN_ERR_SRVCL; // it was a connect error.
4111
willy tarreau0f7af912005-12-17 12:21:26 +01004112 /* if conn_retries < 0 or other error, let's abort */
4113 tv_eternity(&t->cnexpire);
4114 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004115 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004116 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004117 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004118 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004119 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004120 if (!(t->flags & SN_FINST_MASK))
4121 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004122 return 1;
4123 }
4124 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004125 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004126
willy tarreau0f7af912005-12-17 12:21:26 +01004127 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004128 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004129 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004130 tv_eternity(&t->swexpire);
4131 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004132 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004133 if (t->proxy->srvtimeout) {
4134 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4135 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4136 t->srexpire = t->swexpire;
4137 }
4138 else
4139 tv_eternity(&t->swexpire);
4140 }
willy tarreau0f7af912005-12-17 12:21:26 +01004141
4142 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4143 FD_SET(t->srv_fd, StaticReadEvent);
4144 if (t->proxy->srvtimeout)
4145 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4146 else
4147 tv_eternity(&t->srexpire);
4148
4149 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004150 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004151
4152 /* if the user wants to log as soon as possible, without counting
4153 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004154 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004155 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4156 sess_log(t);
4157 }
willy tarreau0f7af912005-12-17 12:21:26 +01004158 }
willy tarreauef900ab2005-12-17 12:52:52 +01004159 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004160 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004161 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4162 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004163 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004164 return 1;
4165 }
4166 }
4167 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004168 /* now parse the partial (or complete) headers */
4169 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4170 char *ptr;
4171 int delete_header;
4172
4173 ptr = rep->lr;
4174
4175 /* look for the end of the current header */
4176 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4177 ptr++;
4178
4179 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004180 int line, len;
4181
4182 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004183
4184 /* first, we'll block if security checks have caught nasty things */
4185 if (t->flags & SN_CACHEABLE) {
4186 if ((t->flags & SN_CACHE_COOK) &&
4187 (t->flags & SN_SCK_ANY) &&
4188 (t->proxy->options & PR_O_CHK_CACHE)) {
4189
4190 /* we're in presence of a cacheable response containing
4191 * a set-cookie header. We'll block it as requested by
4192 * the 'checkcache' option, and send an alert.
4193 */
4194 tv_eternity(&t->srexpire);
4195 tv_eternity(&t->swexpire);
4196 fd_delete(t->srv_fd);
4197 t->srv_state = SV_STCLOSE;
4198 t->logs.status = 502;
4199 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4200 if (!(t->flags & SN_ERR_MASK))
4201 t->flags |= SN_ERR_PRXCOND;
4202 if (!(t->flags & SN_FINST_MASK))
4203 t->flags |= SN_FINST_H;
4204
4205 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4206 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4207
4208 return 1;
4209 }
4210 }
4211
willy tarreau982249e2005-12-18 00:57:06 +01004212 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4213 if (t->flags & SN_SVDENY) {
4214 tv_eternity(&t->srexpire);
4215 tv_eternity(&t->swexpire);
4216 fd_delete(t->srv_fd);
4217 t->srv_state = SV_STCLOSE;
4218 t->logs.status = 502;
4219 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4220 if (!(t->flags & SN_ERR_MASK))
4221 t->flags |= SN_ERR_PRXCOND;
4222 if (!(t->flags & SN_FINST_MASK))
4223 t->flags |= SN_FINST_H;
4224 return 1;
4225 }
4226
willy tarreau5cbea6f2005-12-17 12:48:26 +01004227 /* we'll have something else to do here : add new headers ... */
4228
willy tarreaucd878942005-12-17 13:27:43 +01004229 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4230 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004231 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004232 * insert a set-cookie here, except if we want to insert only on POST
4233 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004234 */
willy tarreau750a4722005-12-17 13:21:24 +01004235 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004236 t->proxy->cookie_name,
4237 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004238
willy tarreau036e1ce2005-12-17 13:46:33 +01004239 t->flags |= SN_SCK_INSERTED;
4240
willy tarreau750a4722005-12-17 13:21:24 +01004241 /* Here, we will tell an eventual cache on the client side that we don't
4242 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4243 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4244 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4245 */
willy tarreau240afa62005-12-17 13:14:35 +01004246 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004247 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4248 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004249
4250 if (rep->data + rep->l < rep->h)
4251 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4252 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004253 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004254 }
4255
4256 /* headers to be added */
4257 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004258 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4259 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004260 }
4261
willy tarreau25c4ea52005-12-18 00:49:49 +01004262 /* add a "connection: close" line if needed */
4263 if (t->proxy->options & PR_O_HTTP_CLOSE)
4264 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4265
willy tarreau5cbea6f2005-12-17 12:48:26 +01004266 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004267 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004268 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004269
Willy TARREAU767ba712006-03-01 22:40:50 +01004270 /* client connection already closed or option 'httpclose' required :
4271 * we close the server's outgoing connection right now.
4272 */
4273 if ((req->l == 0) &&
4274 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4275 FD_CLR(t->srv_fd, StaticWriteEvent);
4276 tv_eternity(&t->swexpire);
4277
4278 /* We must ensure that the read part is still alive when switching
4279 * to shutw */
4280 FD_SET(t->srv_fd, StaticReadEvent);
4281 if (t->proxy->srvtimeout)
4282 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4283
4284 shutdown(t->srv_fd, SHUT_WR);
4285 t->srv_state = SV_STSHUTW;
4286 }
4287
willy tarreau25c4ea52005-12-18 00:49:49 +01004288 /* if the user wants to log as soon as possible, without counting
4289 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004290 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004291 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4292 t->logs.bytes = rep->h - rep->data;
4293 sess_log(t);
4294 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004295 break;
4296 }
4297
4298 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4299 if (ptr > rep->r - 2) {
4300 /* this is a partial header, let's wait for more to come */
4301 rep->lr = ptr;
4302 break;
4303 }
4304
4305 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4306 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4307
4308 /* now we know that *ptr is either \r or \n,
4309 * and that there are at least 1 char after it.
4310 */
4311 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4312 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4313 else
4314 rep->lr = ptr + 2; /* \r\n or \n\r */
4315
4316 /*
4317 * now we know that we have a full header ; we can do whatever
4318 * we want with these pointers :
4319 * rep->h = beginning of header
4320 * ptr = end of header (first \r or \n)
4321 * rep->lr = beginning of next line (next rep->h)
4322 * rep->r = end of data (not used at this stage)
4323 */
4324
willy tarreaua1598082005-12-17 13:08:06 +01004325
willy tarreau982249e2005-12-18 00:57:06 +01004326 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004327 t->logs.logwait &= ~LW_RESP;
4328 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004329 switch (t->logs.status) {
4330 case 200:
4331 case 203:
4332 case 206:
4333 case 300:
4334 case 301:
4335 case 410:
4336 /* RFC2616 @13.4:
4337 * "A response received with a status code of
4338 * 200, 203, 206, 300, 301 or 410 MAY be stored
4339 * by a cache (...) unless a cache-control
4340 * directive prohibits caching."
4341 *
4342 * RFC2616 @9.5: POST method :
4343 * "Responses to this method are not cacheable,
4344 * unless the response includes appropriate
4345 * Cache-Control or Expires header fields."
4346 */
4347 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4348 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4349 break;
4350 default:
4351 break;
4352 }
willy tarreau4302f492005-12-18 01:00:37 +01004353 }
4354 else if (t->logs.logwait & LW_RSPHDR) {
4355 struct cap_hdr *h;
4356 int len;
4357 for (h = t->proxy->rsp_cap; h; h = h->next) {
4358 if ((h->namelen + 2 <= ptr - rep->h) &&
4359 (rep->h[h->namelen] == ':') &&
4360 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4361
4362 if (t->rsp_cap[h->index] == NULL)
4363 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4364
4365 len = ptr - (rep->h + h->namelen + 2);
4366 if (len > h->len)
4367 len = h->len;
4368
4369 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4370 t->rsp_cap[h->index][len]=0;
4371 }
4372 }
4373
willy tarreaua1598082005-12-17 13:08:06 +01004374 }
4375
willy tarreau5cbea6f2005-12-17 12:48:26 +01004376 delete_header = 0;
4377
willy tarreau982249e2005-12-18 00:57:06 +01004378 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004379 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004380 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 +01004381 max = ptr - rep->h;
4382 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004383 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004384 trash[len++] = '\n';
4385 write(1, trash, len);
4386 }
4387
willy tarreau25c4ea52005-12-18 00:49:49 +01004388 /* remove "connection: " if needed */
4389 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4390 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4391 delete_header = 1;
4392 }
4393
willy tarreau5cbea6f2005-12-17 12:48:26 +01004394 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004395 if (!delete_header && t->proxy->rsp_exp != NULL
4396 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004397 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004398 char term;
4399
4400 term = *ptr;
4401 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004402 exp = t->proxy->rsp_exp;
4403 do {
4404 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4405 switch (exp->action) {
4406 case ACT_ALLOW:
4407 if (!(t->flags & SN_SVDENY))
4408 t->flags |= SN_SVALLOW;
4409 break;
4410 case ACT_REPLACE:
4411 if (!(t->flags & SN_SVDENY)) {
4412 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4413 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4414 }
4415 break;
4416 case ACT_REMOVE:
4417 if (!(t->flags & SN_SVDENY))
4418 delete_header = 1;
4419 break;
4420 case ACT_DENY:
4421 if (!(t->flags & SN_SVALLOW))
4422 t->flags |= SN_SVDENY;
4423 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004424 case ACT_PASS: /* we simply don't deny this one */
4425 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004426 }
4427 break;
4428 }
willy tarreaue39cd132005-12-17 13:00:18 +01004429 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004430 *ptr = term; /* restore the string terminator */
4431 }
4432
willy tarreau97f58572005-12-18 00:53:44 +01004433 /* check for cache-control: or pragma: headers */
4434 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4435 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4436 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4437 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4438 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004439 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004440 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4441 else {
4442 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004443 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004444 t->flags &= ~SN_CACHE_COOK;
4445 }
4446 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004447 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004448 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004449 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004450 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4451 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004452 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004453 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004454 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4455 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4456 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4457 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4458 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4459 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004460 }
4461 }
4462 }
4463
willy tarreau5cbea6f2005-12-17 12:48:26 +01004464 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004465 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004466 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004467 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004468 char *p1, *p2, *p3, *p4;
4469
willy tarreau97f58572005-12-18 00:53:44 +01004470 t->flags |= SN_SCK_ANY;
4471
willy tarreau5cbea6f2005-12-17 12:48:26 +01004472 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4473
4474 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004475 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004476 p1++;
4477
4478 if (p1 == ptr || *p1 == ';') /* end of cookie */
4479 break;
4480
4481 /* p1 is at the beginning of the cookie name */
4482 p2 = p1;
4483
4484 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4485 p2++;
4486
4487 if (p2 == ptr || *p2 == ';') /* next cookie */
4488 break;
4489
4490 p3 = p2 + 1; /* skips the '=' sign */
4491 if (p3 == ptr)
4492 break;
4493
4494 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004495 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004496 p4++;
4497
4498 /* here, we have the cookie name between p1 and p2,
4499 * and its value between p3 and p4.
4500 * we can process it.
4501 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004502
4503 /* first, let's see if we want to capture it */
4504 if (t->proxy->capture_name != NULL &&
4505 t->logs.srv_cookie == NULL &&
4506 (p4 - p1 >= t->proxy->capture_namelen) &&
4507 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4508 int log_len = p4 - p1;
4509
4510 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4511 Alert("HTTP logging : out of memory.\n");
4512 }
4513
4514 if (log_len > t->proxy->capture_len)
4515 log_len = t->proxy->capture_len;
4516 memcpy(t->logs.srv_cookie, p1, log_len);
4517 t->logs.srv_cookie[log_len] = 0;
4518 }
4519
4520 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4521 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004522 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004523 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004524
4525 /* If the cookie is in insert mode on a known server, we'll delete
4526 * this occurrence because we'll insert another one later.
4527 * We'll delete it too if the "indirect" option is set and we're in
4528 * a direct access. */
4529 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004530 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004531 /* this header must be deleted */
4532 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004533 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004534 }
4535 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4536 /* replace bytes p3->p4 with the cookie name associated
4537 * with this server since we know it.
4538 */
4539 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004540 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004541 }
willy tarreau0174f312005-12-18 01:02:42 +01004542 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4543 /* insert the cookie name associated with this server
4544 * before existing cookie, and insert a delimitor between them..
4545 */
4546 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4547 p3[t->srv->cklen] = COOKIE_DELIM;
4548 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4549 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004550 break;
4551 }
willy tarreau12350152005-12-18 01:03:27 +01004552
4553 /* first, let's see if the cookie is our appcookie*/
4554 if ((t->proxy->appsession_name != NULL) &&
4555 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4556
4557 /* Cool... it's the right one */
4558
willy tarreaub952e1d2005-12-18 01:31:20 +01004559 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004560 asession_temp = &local_asession;
4561
willy tarreaub952e1d2005-12-18 01:31:20 +01004562 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004563 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4564 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4565 }
4566 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4567 asession_temp->sessid[t->proxy->appsession_len] = 0;
4568 asession_temp->serverid = NULL;
4569
4570 /* only do insert, if lookup fails */
4571 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4572 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4573 Alert("Not enought Memory process_srv():asession:calloc().\n");
4574 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4575 return 0;
4576 }
4577 asession_temp->sessid = local_asession.sessid;
4578 asession_temp->serverid = local_asession.serverid;
4579 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004580 }/* end if (chtbl_lookup()) */
4581 else {
willy tarreau12350152005-12-18 01:03:27 +01004582 /* free wasted memory */
4583 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004584 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004585
willy tarreaub952e1d2005-12-18 01:31:20 +01004586 if (asession_temp->serverid == NULL) {
4587 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004588 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4589 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4590 }
4591 asession_temp->serverid[0] = '\0';
4592 }
4593
willy tarreaub952e1d2005-12-18 01:31:20 +01004594 if (asession_temp->serverid[0] == '\0')
4595 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004596
4597 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4598
4599#if defined(DEBUG_HASH)
4600 print_table(&(t->proxy->htbl_proxy));
4601#endif
4602 break;
4603 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004604 else {
4605 // fprintf(stderr,"Ignoring unknown cookie : ");
4606 // write(2, p1, p2-p1);
4607 // fprintf(stderr," = ");
4608 // write(2, p3, p4-p3);
4609 // fprintf(stderr,"\n");
4610 }
4611 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4612 } /* we're now at the end of the cookie value */
4613 } /* end of cookie processing */
4614
willy tarreau97f58572005-12-18 00:53:44 +01004615 /* check for any set-cookie in case we check for cacheability */
4616 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4617 (t->proxy->options & PR_O_CHK_CACHE) &&
4618 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4619 t->flags |= SN_SCK_ANY;
4620 }
4621
willy tarreau5cbea6f2005-12-17 12:48:26 +01004622 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004623 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004624 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004625
willy tarreau5cbea6f2005-12-17 12:48:26 +01004626 rep->h = rep->lr;
4627 } /* while (rep->lr < rep->r) */
4628
4629 /* end of header processing (even if incomplete) */
4630
willy tarreauef900ab2005-12-17 12:52:52 +01004631 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4632 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4633 * full. We cannot loop here since event_srv_read will disable it only if
4634 * rep->l == rlim-data
4635 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004636 FD_SET(t->srv_fd, StaticReadEvent);
4637 if (t->proxy->srvtimeout)
4638 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4639 else
4640 tv_eternity(&t->srexpire);
4641 }
willy tarreau0f7af912005-12-17 12:21:26 +01004642
willy tarreau8337c6b2005-12-17 13:41:01 +01004643 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004644 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004645 tv_eternity(&t->srexpire);
4646 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004647 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004648 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004649 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004650 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004651 if (!(t->flags & SN_ERR_MASK))
4652 t->flags |= SN_ERR_SRVCL;
4653 if (!(t->flags & SN_FINST_MASK))
4654 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004655 return 1;
4656 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004657 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004658 * since we are in header mode, if there's no space left for headers, we
4659 * won't be able to free more later, so the session will never terminate.
4660 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004661 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 +01004662 FD_CLR(t->srv_fd, StaticReadEvent);
4663 tv_eternity(&t->srexpire);
4664 shutdown(t->srv_fd, SHUT_RD);
4665 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004666 //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 +01004667 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004668 }
4669 /* read timeout : return a 504 to the client.
4670 */
4671 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4672 tv_eternity(&t->srexpire);
4673 tv_eternity(&t->swexpire);
4674 fd_delete(t->srv_fd);
4675 t->srv_state = SV_STCLOSE;
4676 t->logs.status = 504;
4677 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004678 if (!(t->flags & SN_ERR_MASK))
4679 t->flags |= SN_ERR_SRVTO;
4680 if (!(t->flags & SN_FINST_MASK))
4681 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004682 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004683
4684 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004685 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004686 /* FIXME!!! here, we don't want to switch to SHUTW if the
4687 * client shuts read too early, because we may still have
4688 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004689 * The side-effect is that if the client completely closes its
4690 * connection during SV_STHEADER, the connection to the server
4691 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004692 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004693 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004694 FD_CLR(t->srv_fd, StaticWriteEvent);
4695 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004696
4697 /* We must ensure that the read part is still alive when switching
4698 * to shutw */
4699 FD_SET(t->srv_fd, StaticReadEvent);
4700 if (t->proxy->srvtimeout)
4701 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4702
willy tarreau0f7af912005-12-17 12:21:26 +01004703 shutdown(t->srv_fd, SHUT_WR);
4704 t->srv_state = SV_STSHUTW;
4705 return 1;
4706 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004707 /* write timeout */
4708 /* FIXME!!! here, we don't want to switch to SHUTW if the
4709 * client shuts read too early, because we may still have
4710 * some work to do on the headers.
4711 */
4712 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4713 FD_CLR(t->srv_fd, StaticWriteEvent);
4714 tv_eternity(&t->swexpire);
4715 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004716 /* We must ensure that the read part is still alive when switching
4717 * to shutw */
4718 FD_SET(t->srv_fd, StaticReadEvent);
4719 if (t->proxy->srvtimeout)
4720 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4721
4722 /* 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
willy tarreau036e1ce2005-12-17 13:46:33 +01004728 t->srv_state = SV_STSHUTW;
4729 if (!(t->flags & SN_ERR_MASK))
4730 t->flags |= SN_ERR_SRVTO;
4731 if (!(t->flags & SN_FINST_MASK))
4732 t->flags |= SN_FINST_H;
4733 return 1;
4734 }
willy tarreau0f7af912005-12-17 12:21:26 +01004735
4736 if (req->l == 0) {
4737 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4738 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4739 tv_eternity(&t->swexpire);
4740 }
4741 }
4742 else { /* client buffer not empty */
4743 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4744 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004745 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004746 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004747 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4748 t->srexpire = t->swexpire;
4749 }
willy tarreau0f7af912005-12-17 12:21:26 +01004750 else
4751 tv_eternity(&t->swexpire);
4752 }
4753 }
4754
willy tarreau5cbea6f2005-12-17 12:48:26 +01004755 /* be nice with the client side which would like to send a complete header
4756 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4757 * would read all remaining data at once ! The client should not write past rep->lr
4758 * when the server is in header state.
4759 */
4760 //return header_processed;
4761 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004762 }
4763 else if (s == SV_STDATA) {
4764 /* read or write error */
4765 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004766 tv_eternity(&t->srexpire);
4767 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004768 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004769 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004770 if (!(t->flags & SN_ERR_MASK))
4771 t->flags |= SN_ERR_SRVCL;
4772 if (!(t->flags & SN_FINST_MASK))
4773 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004774 return 1;
4775 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004776 /* last read, or end of client write */
4777 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004778 FD_CLR(t->srv_fd, StaticReadEvent);
4779 tv_eternity(&t->srexpire);
4780 shutdown(t->srv_fd, SHUT_RD);
4781 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004782 //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 +01004783 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004784 }
4785 /* end of client read and no more data to send */
4786 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4787 FD_CLR(t->srv_fd, StaticWriteEvent);
4788 tv_eternity(&t->swexpire);
4789 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004790 /* We must ensure that the read part is still alive when switching
4791 * to shutw */
4792 FD_SET(t->srv_fd, StaticReadEvent);
4793 if (t->proxy->srvtimeout)
4794 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4795
willy tarreaua41a8b42005-12-17 14:02:24 +01004796 t->srv_state = SV_STSHUTW;
4797 return 1;
4798 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004799 /* read timeout */
4800 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4801 FD_CLR(t->srv_fd, StaticReadEvent);
4802 tv_eternity(&t->srexpire);
4803 shutdown(t->srv_fd, SHUT_RD);
4804 t->srv_state = SV_STSHUTR;
4805 if (!(t->flags & SN_ERR_MASK))
4806 t->flags |= SN_ERR_SRVTO;
4807 if (!(t->flags & SN_FINST_MASK))
4808 t->flags |= SN_FINST_D;
4809 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004810 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004811 /* write timeout */
4812 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004813 FD_CLR(t->srv_fd, StaticWriteEvent);
4814 tv_eternity(&t->swexpire);
4815 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004816 /* We must ensure that the read part is still alive when switching
4817 * to shutw */
4818 FD_SET(t->srv_fd, StaticReadEvent);
4819 if (t->proxy->srvtimeout)
4820 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004821 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004822 if (!(t->flags & SN_ERR_MASK))
4823 t->flags |= SN_ERR_SRVTO;
4824 if (!(t->flags & SN_FINST_MASK))
4825 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004826 return 1;
4827 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004828
4829 /* recompute request time-outs */
4830 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004831 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4832 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4833 tv_eternity(&t->swexpire);
4834 }
4835 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004836 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004837 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4838 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004839 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004840 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004841 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4842 t->srexpire = t->swexpire;
4843 }
willy tarreau0f7af912005-12-17 12:21:26 +01004844 else
4845 tv_eternity(&t->swexpire);
4846 }
4847 }
4848
willy tarreaub1ff9db2005-12-17 13:51:03 +01004849 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004850 if (rep->l == BUFSIZE) { /* no room to read more data */
4851 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4852 FD_CLR(t->srv_fd, StaticReadEvent);
4853 tv_eternity(&t->srexpire);
4854 }
4855 }
4856 else {
4857 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4858 FD_SET(t->srv_fd, StaticReadEvent);
4859 if (t->proxy->srvtimeout)
4860 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4861 else
4862 tv_eternity(&t->srexpire);
4863 }
4864 }
4865
4866 return 0; /* other cases change nothing */
4867 }
4868 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004869 if (t->res_sw == RES_ERROR) {
4870 //FD_CLR(t->srv_fd, StaticWriteEvent);
4871 tv_eternity(&t->swexpire);
4872 fd_delete(t->srv_fd);
4873 //close(t->srv_fd);
4874 t->srv_state = SV_STCLOSE;
4875 if (!(t->flags & SN_ERR_MASK))
4876 t->flags |= SN_ERR_SRVCL;
4877 if (!(t->flags & SN_FINST_MASK))
4878 t->flags |= SN_FINST_D;
4879 return 1;
4880 }
4881 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004882 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004883 tv_eternity(&t->swexpire);
4884 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004885 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004886 t->srv_state = SV_STCLOSE;
4887 return 1;
4888 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004889 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4890 //FD_CLR(t->srv_fd, StaticWriteEvent);
4891 tv_eternity(&t->swexpire);
4892 fd_delete(t->srv_fd);
4893 //close(t->srv_fd);
4894 t->srv_state = SV_STCLOSE;
4895 if (!(t->flags & SN_ERR_MASK))
4896 t->flags |= SN_ERR_SRVTO;
4897 if (!(t->flags & SN_FINST_MASK))
4898 t->flags |= SN_FINST_D;
4899 return 1;
4900 }
willy tarreau0f7af912005-12-17 12:21:26 +01004901 else if (req->l == 0) {
4902 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4903 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4904 tv_eternity(&t->swexpire);
4905 }
4906 }
4907 else { /* buffer not empty */
4908 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4909 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004910 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004911 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004912 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4913 t->srexpire = t->swexpire;
4914 }
willy tarreau0f7af912005-12-17 12:21:26 +01004915 else
4916 tv_eternity(&t->swexpire);
4917 }
4918 }
4919 return 0;
4920 }
4921 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004922 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004923 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004924 tv_eternity(&t->srexpire);
4925 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004926 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004927 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004928 if (!(t->flags & SN_ERR_MASK))
4929 t->flags |= SN_ERR_SRVCL;
4930 if (!(t->flags & SN_FINST_MASK))
4931 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004932 return 1;
4933 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004934 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4935 //FD_CLR(t->srv_fd, StaticReadEvent);
4936 tv_eternity(&t->srexpire);
4937 fd_delete(t->srv_fd);
4938 //close(t->srv_fd);
4939 t->srv_state = SV_STCLOSE;
4940 return 1;
4941 }
4942 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4943 //FD_CLR(t->srv_fd, StaticReadEvent);
4944 tv_eternity(&t->srexpire);
4945 fd_delete(t->srv_fd);
4946 //close(t->srv_fd);
4947 t->srv_state = SV_STCLOSE;
4948 if (!(t->flags & SN_ERR_MASK))
4949 t->flags |= SN_ERR_SRVTO;
4950 if (!(t->flags & SN_FINST_MASK))
4951 t->flags |= SN_FINST_D;
4952 return 1;
4953 }
willy tarreau0f7af912005-12-17 12:21:26 +01004954 else if (rep->l == BUFSIZE) { /* no room to read more data */
4955 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4956 FD_CLR(t->srv_fd, StaticReadEvent);
4957 tv_eternity(&t->srexpire);
4958 }
4959 }
4960 else {
4961 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4962 FD_SET(t->srv_fd, StaticReadEvent);
4963 if (t->proxy->srvtimeout)
4964 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4965 else
4966 tv_eternity(&t->srexpire);
4967 }
4968 }
4969 return 0;
4970 }
4971 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004972 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004973 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004974 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 +01004975 write(1, trash, len);
4976 }
4977 return 0;
4978 }
4979 return 0;
4980}
4981
4982
willy tarreau5cbea6f2005-12-17 12:48:26 +01004983/* Processes the client and server jobs of a session task, then
4984 * puts it back to the wait queue in a clean state, or
4985 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01004986 * the time the task accepts to wait, or TIME_ETERNITY for
4987 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01004988 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004989int process_session(struct task *t) {
4990 struct session *s = t->context;
4991 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004992
willy tarreau5cbea6f2005-12-17 12:48:26 +01004993 do {
4994 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01004995 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004996 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01004997 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004998 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01004999 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005000 } while (fsm_resync);
5001
5002 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005003 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005004 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005005
willy tarreau5cbea6f2005-12-17 12:48:26 +01005006 tv_min(&min1, &s->crexpire, &s->cwexpire);
5007 tv_min(&min2, &s->srexpire, &s->swexpire);
5008 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005009 tv_min(&t->expire, &min1, &min2);
5010
5011 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005012 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005013
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005014#ifdef DEBUG_FULL
5015 /* DEBUG code : this should never ever happen, otherwise it indicates
5016 * that a task still has something to do and will provoke a quick loop.
5017 */
5018 if (tv_remain2(&now, &t->expire) <= 0)
5019 exit(100);
5020#endif
5021
willy tarreaub952e1d2005-12-18 01:31:20 +01005022 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005023 }
5024
willy tarreau5cbea6f2005-12-17 12:48:26 +01005025 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005026 actconn--;
5027
willy tarreau982249e2005-12-18 00:57:06 +01005028 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005029 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005030 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 +01005031 write(1, trash, len);
5032 }
5033
willy tarreau750a4722005-12-17 13:21:24 +01005034 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005035 if (s->rep != NULL)
5036 s->logs.bytes = s->rep->total;
5037
willy tarreau9fe663a2005-12-17 13:02:59 +01005038 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005039 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005040 sess_log(s);
5041
willy tarreau0f7af912005-12-17 12:21:26 +01005042 /* the task MUST not be in the run queue anymore */
5043 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005044 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005045 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005046 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005047}
5048
5049
5050
5051/*
5052 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005053 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005054 */
5055int process_chk(struct task *t) {
5056 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005057 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005058 int fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005059
willy tarreauef900ab2005-12-17 12:52:52 +01005060 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005061
5062 if (fd < 0) { /* no check currently running */
5063 //fprintf(stderr, "process_chk: 2\n");
5064 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5065 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005066 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005067 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005068
5069 /* we don't send any health-checks when the proxy is stopped or when
5070 * the server should not be checked.
5071 */
5072 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
5073 tv_delayfrom(&t->expire, &now, s->inter);
5074 task_queue(t); /* restore t to its place in the task list */
5075 return tv_remain2(&now, &t->expire);
5076 }
5077
willy tarreau5cbea6f2005-12-17 12:48:26 +01005078 /* we'll initiate a new check */
5079 s->result = 0; /* no result yet */
5080 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005081 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005082 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5083 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5084 //fprintf(stderr, "process_chk: 3\n");
5085
willy tarreaua41a8b42005-12-17 14:02:24 +01005086 /* we'll connect to the check port on the server */
5087 sa = s->addr;
5088 sa.sin_port = htons(s->check_port);
5089
willy tarreau0174f312005-12-18 01:02:42 +01005090 /* allow specific binding :
5091 * - server-specific at first
5092 * - proxy-specific next
5093 */
5094 if (s->state & SRV_BIND_SRC) {
5095 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5096 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5097 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5098 s->proxy->id, s->id);
5099 s->result = -1;
5100 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005101 }
willy tarreau0174f312005-12-18 01:02:42 +01005102 else if (s->proxy->options & PR_O_BIND_SRC) {
5103 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5104 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5105 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5106 s->proxy->id);
5107 s->result = -1;
5108 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005109 }
willy tarreau0174f312005-12-18 01:02:42 +01005110
5111 if (!s->result) {
5112 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5113 /* OK, connection in progress or established */
5114
5115 //fprintf(stderr, "process_chk: 4\n");
5116
5117 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5118 fdtab[fd].owner = t;
5119 fdtab[fd].read = &event_srv_chk_r;
5120 fdtab[fd].write = &event_srv_chk_w;
5121 fdtab[fd].state = FD_STCONN; /* connection in progress */
5122 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005123#ifdef DEBUG_FULL
5124 assert (!FD_ISSET(fd, StaticReadEvent));
5125#endif
willy tarreau0174f312005-12-18 01:02:42 +01005126 fd_insert(fd);
5127 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5128 tv_delayfrom(&t->expire, &now, s->inter);
5129 task_queue(t); /* restore t to its place in the task list */
5130 return tv_remain(&now, &t->expire);
5131 }
5132 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5133 s->result = -1; /* a real error */
5134 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005135 }
5136 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005137 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005138 }
5139
5140 if (!s->result) { /* nothing done */
5141 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005142 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005143 task_queue(t); /* restore t to its place in the task list */
5144 return tv_remain(&now, &t->expire);
5145 }
5146
5147 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005148 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005149 s->health--; /* still good */
5150 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005151 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005152 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005153 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005154 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01005155
willy tarreaudd07e972005-12-18 00:48:48 +01005156 if (find_server(s->proxy) == NULL) {
5157 Alert("Proxy %s has no server available !\n", s->proxy->id);
5158 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5159 }
5160 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005161 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005162 }
5163
5164 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005165 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5166 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005167 }
5168 else {
5169 //fprintf(stderr, "process_chk: 8\n");
5170 /* there was a test running */
5171 if (s->result > 0) { /* good server detected */
5172 //fprintf(stderr, "process_chk: 9\n");
5173 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005174 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005175 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005176 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005177 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005178 }
willy tarreauef900ab2005-12-17 12:52:52 +01005179
willy tarreaue47c8d72005-12-17 12:55:52 +01005180 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005181 s->state |= SRV_RUNNING;
5182 }
willy tarreauef900ab2005-12-17 12:52:52 +01005183 s->curfd = -1; /* no check running anymore */
5184 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005185 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005186 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005187 }
5188 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5189 //fprintf(stderr, "process_chk: 10\n");
5190 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005191 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005192 s->health--; /* still good */
5193 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005194 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005195
willy tarreaudd07e972005-12-18 00:48:48 +01005196 if (s->health == s->rise) {
5197 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005198 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01005199
5200 if (find_server(s->proxy) == NULL) {
5201 Alert("Proxy %s has no server available !\n", s->proxy->id);
5202 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5203 }
willy tarreau535ae7a2005-12-17 12:58:00 +01005204 }
willy tarreauef900ab2005-12-17 12:52:52 +01005205
willy tarreau5cbea6f2005-12-17 12:48:26 +01005206 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005207 }
5208 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005209 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005210 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005211 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005212 }
5213 /* if result is 0 and there's no timeout, we have to wait again */
5214 }
5215 //fprintf(stderr, "process_chk: 11\n");
5216 s->result = 0;
5217 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005218 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005219}
5220
5221
willy tarreau5cbea6f2005-12-17 12:48:26 +01005222
willy tarreau0f7af912005-12-17 12:21:26 +01005223#if STATTIME > 0
5224int stats(void);
5225#endif
5226
5227/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005228 * This does 4 things :
5229 * - wake up all expired tasks
5230 * - call all runnable tasks
5231 * - call maintain_proxies() to enable/disable the listeners
5232 * - return the delay till next event in ms, -1 = wait indefinitely
5233 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5234 *
willy tarreau0f7af912005-12-17 12:21:26 +01005235 */
5236
willy tarreau1c2ad212005-12-18 01:11:29 +01005237int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005238 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005239 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005240 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005241
willy tarreaub952e1d2005-12-18 01:31:20 +01005242 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005243
willy tarreau1c2ad212005-12-18 01:11:29 +01005244 /* look for expired tasks and add them to the run queue.
5245 */
5246 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5247 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5248 tnext = t->next;
5249 if (t->state & TASK_RUNNING)
5250 continue;
5251
willy tarreaub952e1d2005-12-18 01:31:20 +01005252 if (tv_iseternity(&t->expire))
5253 continue;
5254
willy tarreau1c2ad212005-12-18 01:11:29 +01005255 /* wakeup expired entries. It doesn't matter if they are
5256 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005257 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005258 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005259 task_wakeup(&rq, t);
5260 }
5261 else {
5262 /* first non-runnable task. Use its expiration date as an upper bound */
5263 int temp_time = tv_remain(&now, &t->expire);
5264 if (temp_time)
5265 next_time = temp_time;
5266 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005267 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005268 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005269
willy tarreau1c2ad212005-12-18 01:11:29 +01005270 /* process each task in the run queue now. Each task may be deleted
5271 * since we only use tnext.
5272 */
5273 tnext = rq;
5274 while ((t = tnext) != NULL) {
5275 int temp_time;
5276
5277 tnext = t->rqnext;
5278 task_sleep(&rq, t);
5279 temp_time = t->process(t);
5280 next_time = MINTIME(temp_time, next_time);
5281 }
5282
5283 /* maintain all proxies in a consistent state. This should quickly become a task */
5284 time2 = maintain_proxies();
5285 return MINTIME(time2, next_time);
5286}
5287
5288
5289#if defined(ENABLE_EPOLL)
5290
5291/*
5292 * Main epoll() loop.
5293 */
5294
5295/* does 3 actions :
5296 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5297 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5298 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5299 *
5300 * returns 0 if initialization failed, !0 otherwise.
5301 */
5302
5303int epoll_loop(int action) {
5304 int next_time;
5305 int status;
5306 int fd;
5307
5308 int fds, count;
5309 int pr, pw, sr, sw;
5310 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5311 struct epoll_event ev;
5312
5313 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005314 static struct epoll_event *epoll_events = NULL;
5315 static int epoll_fd;
5316
5317 if (action == POLL_LOOP_ACTION_INIT) {
5318 epoll_fd = epoll_create(global.maxsock + 1);
5319 if (epoll_fd < 0)
5320 return 0;
5321 else {
5322 epoll_events = (struct epoll_event*)
5323 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5324 PrevReadEvent = (fd_set *)
5325 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5326 PrevWriteEvent = (fd_set *)
5327 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005328 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005329 return 1;
5330 }
5331 else if (action == POLL_LOOP_ACTION_CLEAN) {
5332 if (PrevWriteEvent) free(PrevWriteEvent);
5333 if (PrevReadEvent) free(PrevReadEvent);
5334 if (epoll_events) free(epoll_events);
5335 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005336 epoll_fd = 0;
5337 return 1;
5338 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005339
willy tarreau1c2ad212005-12-18 01:11:29 +01005340 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005341
willy tarreau1c2ad212005-12-18 01:11:29 +01005342 tv_now(&now);
5343
5344 while (1) {
5345 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005346
5347 /* stop when there's no connection left and we don't allow them anymore */
5348 if (!actconn && listeners == 0)
5349 break;
5350
willy tarreau0f7af912005-12-17 12:21:26 +01005351#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005352 {
5353 int time2;
5354 time2 = stats();
5355 next_time = MINTIME(time2, next_time);
5356 }
willy tarreau0f7af912005-12-17 12:21:26 +01005357#endif
5358
willy tarreau1c2ad212005-12-18 01:11:29 +01005359 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5360
5361 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5362 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5363
5364 if ((ro^rn) | (wo^wn)) {
5365 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5366#define FDSETS_ARE_INT_ALIGNED
5367#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005368
willy tarreauad90a0c2005-12-18 01:09:15 +01005369#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5370#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005371 pr = (ro >> count) & 1;
5372 pw = (wo >> count) & 1;
5373 sr = (rn >> count) & 1;
5374 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005375#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005376 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5377 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5378 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5379 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005380#endif
5381#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005382 pr = FD_ISSET(fd, PrevReadEvent);
5383 pw = FD_ISSET(fd, PrevWriteEvent);
5384 sr = FD_ISSET(fd, StaticReadEvent);
5385 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005386#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005387 if (!((sr^pr) | (sw^pw)))
5388 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005389
willy tarreau1c2ad212005-12-18 01:11:29 +01005390 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5391 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005392
willy tarreaub952e1d2005-12-18 01:31:20 +01005393#ifdef EPOLL_CTL_MOD_WORKAROUND
5394 /* I encountered a rarely reproducible problem with
5395 * EPOLL_CTL_MOD where a modified FD (systematically
5396 * the one in epoll_events[0], fd#7) would sometimes
5397 * be set EPOLL_OUT while asked for a read ! This is
5398 * with the 2.4 epoll patch. The workaround is to
5399 * delete then recreate in case of modification.
5400 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5401 * nor RHEL kernels.
5402 */
5403
5404 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5405 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5406
5407 if ((sr | sw))
5408 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5409#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005410 if ((pr | pw)) {
5411 /* the file-descriptor already exists... */
5412 if ((sr | sw)) {
5413 /* ...and it will still exist */
5414 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5415 // perror("epoll_ctl(MOD)");
5416 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005417 }
5418 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005419 /* ...and it will be removed */
5420 if (fdtab[fd].state != FD_STCLOSE &&
5421 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5422 // perror("epoll_ctl(DEL)");
5423 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005424 }
5425 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005426 } else {
5427 /* the file-descriptor did not exist, let's add it */
5428 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5429 // perror("epoll_ctl(ADD)");
5430 // exit(1);
5431 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005432 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005433#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005434 }
5435 ((int*)PrevReadEvent)[fds] = rn;
5436 ((int*)PrevWriteEvent)[fds] = wn;
5437 }
5438 }
5439
5440 /* now let's wait for events */
5441 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5442 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005443
willy tarreau1c2ad212005-12-18 01:11:29 +01005444 for (count = 0; count < status; count++) {
5445 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01005446
5447 if (FD_ISSET(fd, StaticReadEvent)) {
5448 if (fdtab[fd].state == FD_STCLOSE)
5449 continue;
5450 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5451 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005452 }
willy tarreau05be12b2006-03-19 19:35:00 +01005453
5454 if (FD_ISSET(fd, StaticWriteEvent)) {
5455 if (fdtab[fd].state == FD_STCLOSE)
5456 continue;
5457 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5458 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005459 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005460 }
5461 }
5462 return 1;
5463}
5464#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005465
willy tarreauad90a0c2005-12-18 01:09:15 +01005466
willy tarreau5cbea6f2005-12-17 12:48:26 +01005467
willy tarreau1c2ad212005-12-18 01:11:29 +01005468#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005469
willy tarreau1c2ad212005-12-18 01:11:29 +01005470/*
5471 * Main poll() loop.
5472 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005473
willy tarreau1c2ad212005-12-18 01:11:29 +01005474/* does 3 actions :
5475 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5476 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5477 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5478 *
5479 * returns 0 if initialization failed, !0 otherwise.
5480 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005481
willy tarreau1c2ad212005-12-18 01:11:29 +01005482int poll_loop(int action) {
5483 int next_time;
5484 int status;
5485 int fd, nbfd;
5486
5487 int fds, count;
5488 int sr, sw;
5489 unsigned rn, wn; /* read new, write new */
5490
5491 /* private data */
5492 static struct pollfd *poll_events = NULL;
5493
5494 if (action == POLL_LOOP_ACTION_INIT) {
5495 poll_events = (struct pollfd*)
5496 calloc(1, sizeof(struct pollfd) * global.maxsock);
5497 return 1;
5498 }
5499 else if (action == POLL_LOOP_ACTION_CLEAN) {
5500 if (poll_events)
5501 free(poll_events);
5502 return 1;
5503 }
5504
5505 /* OK, it's POLL_LOOP_ACTION_RUN */
5506
5507 tv_now(&now);
5508
5509 while (1) {
5510 next_time = process_runnable_tasks();
5511
5512 /* stop when there's no connection left and we don't allow them anymore */
5513 if (!actconn && listeners == 0)
5514 break;
5515
5516#if STATTIME > 0
5517 {
5518 int time2;
5519 time2 = stats();
5520 next_time = MINTIME(time2, next_time);
5521 }
5522#endif
5523
5524
5525 nbfd = 0;
5526 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5527
5528 rn = ((int*)StaticReadEvent)[fds];
5529 wn = ((int*)StaticWriteEvent)[fds];
5530
5531 if ((rn|wn)) {
5532 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5533#define FDSETS_ARE_INT_ALIGNED
5534#ifdef FDSETS_ARE_INT_ALIGNED
5535
5536#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5537#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5538 sr = (rn >> count) & 1;
5539 sw = (wn >> count) & 1;
5540#else
5541 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5542 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5543#endif
5544#else
5545 sr = FD_ISSET(fd, StaticReadEvent);
5546 sw = FD_ISSET(fd, StaticWriteEvent);
5547#endif
5548 if ((sr|sw)) {
5549 poll_events[nbfd].fd = fd;
5550 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5551 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005552 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005553 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005554 }
5555 }
5556
5557 /* now let's wait for events */
5558 status = poll(poll_events, nbfd, next_time);
5559 tv_now(&now);
5560
5561 for (count = 0; status > 0 && count < nbfd; count++) {
5562 fd = poll_events[count].fd;
5563
5564 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5565 continue;
5566
5567 /* ok, we found one active fd */
5568 status--;
5569
willy tarreau05be12b2006-03-19 19:35:00 +01005570 if (FD_ISSET(fd, StaticReadEvent)) {
5571 if (fdtab[fd].state == FD_STCLOSE)
5572 continue;
5573 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5574 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005575 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005576
willy tarreau05be12b2006-03-19 19:35:00 +01005577 if (FD_ISSET(fd, StaticWriteEvent)) {
5578 if (fdtab[fd].state == FD_STCLOSE)
5579 continue;
5580 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5581 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005582 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005583 }
5584 }
5585 return 1;
5586}
willy tarreauad90a0c2005-12-18 01:09:15 +01005587#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005588
willy tarreauad90a0c2005-12-18 01:09:15 +01005589
willy tarreauad90a0c2005-12-18 01:09:15 +01005590
willy tarreau1c2ad212005-12-18 01:11:29 +01005591/*
5592 * Main select() loop.
5593 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005594
willy tarreau1c2ad212005-12-18 01:11:29 +01005595/* does 3 actions :
5596 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5597 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5598 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5599 *
5600 * returns 0 if initialization failed, !0 otherwise.
5601 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005602
willy tarreauad90a0c2005-12-18 01:09:15 +01005603
willy tarreau1c2ad212005-12-18 01:11:29 +01005604int select_loop(int action) {
5605 int next_time;
5606 int status;
5607 int fd,i;
5608 struct timeval delta;
5609 int readnotnull, writenotnull;
5610 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005611
willy tarreau1c2ad212005-12-18 01:11:29 +01005612 if (action == POLL_LOOP_ACTION_INIT) {
5613 ReadEvent = (fd_set *)
5614 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5615 WriteEvent = (fd_set *)
5616 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5617 return 1;
5618 }
5619 else if (action == POLL_LOOP_ACTION_CLEAN) {
5620 if (WriteEvent) free(WriteEvent);
5621 if (ReadEvent) free(ReadEvent);
5622 return 1;
5623 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005624
willy tarreau1c2ad212005-12-18 01:11:29 +01005625 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005626
willy tarreau1c2ad212005-12-18 01:11:29 +01005627 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005628
willy tarreau1c2ad212005-12-18 01:11:29 +01005629 while (1) {
5630 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005631
willy tarreau1c2ad212005-12-18 01:11:29 +01005632 /* stop when there's no connection left and we don't allow them anymore */
5633 if (!actconn && listeners == 0)
5634 break;
5635
5636#if STATTIME > 0
5637 {
5638 int time2;
5639 time2 = stats();
5640 next_time = MINTIME(time2, next_time);
5641 }
5642#endif
5643
willy tarreau1c2ad212005-12-18 01:11:29 +01005644 if (next_time > 0) { /* FIXME */
5645 /* Convert to timeval */
5646 /* to avoid eventual select loops due to timer precision */
5647 next_time += SCHEDULER_RESOLUTION;
5648 delta.tv_sec = next_time / 1000;
5649 delta.tv_usec = (next_time % 1000) * 1000;
5650 }
5651 else if (next_time == 0) { /* allow select to return immediately when needed */
5652 delta.tv_sec = delta.tv_usec = 0;
5653 }
5654
5655
5656 /* let's restore fdset state */
5657
5658 readnotnull = 0; writenotnull = 0;
5659 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5660 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5661 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5662 }
5663
5664 // /* just a verification code, needs to be removed for performance */
5665 // for (i=0; i<maxfd; i++) {
5666 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5667 // abort();
5668 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5669 // abort();
5670 //
5671 // }
5672
5673 status = select(maxfd,
5674 readnotnull ? ReadEvent : NULL,
5675 writenotnull ? WriteEvent : NULL,
5676 NULL,
5677 (next_time >= 0) ? &delta : NULL);
5678
5679 /* this is an experiment on the separation of the select work */
5680 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5681 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5682
5683 tv_now(&now);
5684
5685 if (status > 0) { /* must proceed with events */
5686
5687 int fds;
5688 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005689
willy tarreau1c2ad212005-12-18 01:11:29 +01005690 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5691 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5692 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5693
5694 /* if we specify read first, the accepts and zero reads will be
5695 * seen first. Moreover, system buffers will be flushed faster.
5696 */
willy tarreau05be12b2006-03-19 19:35:00 +01005697 if (FD_ISSET(fd, ReadEvent)) {
5698 if (fdtab[fd].state == FD_STCLOSE)
5699 continue;
5700 fdtab[fd].read(fd);
5701 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005702
willy tarreau05be12b2006-03-19 19:35:00 +01005703 if (FD_ISSET(fd, WriteEvent)) {
5704 if (fdtab[fd].state == FD_STCLOSE)
5705 continue;
5706 fdtab[fd].write(fd);
5707 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005708 }
5709 }
5710 else {
5711 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005712 }
willy tarreau0f7af912005-12-17 12:21:26 +01005713 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005714 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005715}
5716
5717
5718#if STATTIME > 0
5719/*
5720 * Display proxy statistics regularly. It is designed to be called from the
5721 * select_loop().
5722 */
5723int stats(void) {
5724 static int lines;
5725 static struct timeval nextevt;
5726 static struct timeval lastevt;
5727 static struct timeval starttime = {0,0};
5728 unsigned long totaltime, deltatime;
5729 int ret;
5730
willy tarreau750a4722005-12-17 13:21:24 +01005731 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005732 deltatime = (tv_diff(&lastevt, &now)?:1);
5733 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005734
willy tarreau9fe663a2005-12-17 13:02:59 +01005735 if (global.mode & MODE_STATS) {
5736 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005737 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005738 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5739 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005740 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005741 actconn, totalconn,
5742 stats_tsk_new, stats_tsk_good,
5743 stats_tsk_left, stats_tsk_right,
5744 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5745 }
5746 }
5747
5748 tv_delayfrom(&nextevt, &now, STATTIME);
5749
5750 lastevt=now;
5751 }
5752 ret = tv_remain(&now, &nextevt);
5753 return ret;
5754}
5755#endif
5756
5757
5758/*
5759 * this function enables proxies when there are enough free sessions,
5760 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005761 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005762 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005763 */
5764static int maintain_proxies(void) {
5765 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005766 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005767 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005768
5769 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005770 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005771
5772 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005773 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005774 while (p) {
5775 if (p->nbconn < p->maxconn) {
5776 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005777 for (l = p->listen; l != NULL; l = l->next) {
5778 FD_SET(l->fd, StaticReadEvent);
5779 }
willy tarreau0f7af912005-12-17 12:21:26 +01005780 p->state = PR_STRUN;
5781 }
5782 }
5783 else {
5784 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005785 for (l = p->listen; l != NULL; l = l->next) {
5786 FD_CLR(l->fd, StaticReadEvent);
5787 }
willy tarreau0f7af912005-12-17 12:21:26 +01005788 p->state = PR_STIDLE;
5789 }
5790 }
5791 p = p->next;
5792 }
5793 }
5794 else { /* block all proxies */
5795 while (p) {
5796 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005797 for (l = p->listen; l != NULL; l = l->next) {
5798 FD_CLR(l->fd, StaticReadEvent);
5799 }
willy tarreau0f7af912005-12-17 12:21:26 +01005800 p->state = PR_STIDLE;
5801 }
5802 p = p->next;
5803 }
5804 }
5805
willy tarreau5cbea6f2005-12-17 12:48:26 +01005806 if (stopping) {
5807 p = proxy;
5808 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01005809 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005810 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01005811 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005812 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005813 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005814 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005815
willy tarreaua41a8b42005-12-17 14:02:24 +01005816 for (l = p->listen; l != NULL; l = l->next) {
5817 fd_delete(l->fd);
5818 listeners--;
5819 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01005820 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005821 }
5822 else {
5823 tleft = MINTIME(t, tleft);
5824 }
5825 }
5826 p = p->next;
5827 }
5828 }
5829 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01005830}
5831
5832/*
5833 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01005834 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
5835 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01005836 */
5837static void soft_stop(void) {
5838 struct proxy *p;
5839
5840 stopping = 1;
5841 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005842 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01005843 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01005844 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005845 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01005846 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01005847 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01005848 }
willy tarreau0f7af912005-12-17 12:21:26 +01005849 p = p->next;
5850 }
5851}
5852
willy tarreaudbd3bef2006-01-20 19:35:18 +01005853static void pause_proxy(struct proxy *p) {
5854 struct listener *l;
5855 for (l = p->listen; l != NULL; l = l->next) {
5856 shutdown(l->fd, SHUT_RD);
5857 FD_CLR(l->fd, StaticReadEvent);
5858 p->state = PR_STPAUSED;
5859 }
5860}
5861
5862/*
5863 * This function temporarily disables listening so that another new instance
5864 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01005865 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01005866 * the proxy, or a SIGTTIN can be sent to listen again.
5867 */
5868static void pause_proxies(void) {
5869 struct proxy *p;
5870
5871 p = proxy;
5872 tv_now(&now); /* else, the old time before select will be used */
5873 while (p) {
5874 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
5875 Warning("Pausing proxy %s.\n", p->id);
5876 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
5877 pause_proxy(p);
5878 }
5879 p = p->next;
5880 }
5881}
5882
5883
5884/*
5885 * This function reactivates listening. This can be used after a call to
5886 * sig_pause(), for example when a new instance has failed starting up.
5887 * It is designed to be called upon reception of a SIGTTIN.
5888 */
5889static void listen_proxies(void) {
5890 struct proxy *p;
5891 struct listener *l;
5892
5893 p = proxy;
5894 tv_now(&now); /* else, the old time before select will be used */
5895 while (p) {
5896 if (p->state == PR_STPAUSED) {
5897 Warning("Enabling proxy %s.\n", p->id);
5898 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
5899
5900 for (l = p->listen; l != NULL; l = l->next) {
5901 if (listen(l->fd, p->maxconn) == 0) {
5902 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
5903 FD_SET(l->fd, StaticReadEvent);
5904 p->state = PR_STRUN;
5905 }
5906 else
5907 p->state = PR_STIDLE;
5908 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01005909 int port;
5910
5911 if (l->addr.ss_family == AF_INET6)
5912 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
5913 else
5914 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
5915
willy tarreaudbd3bef2006-01-20 19:35:18 +01005916 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01005917 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01005918 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01005919 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01005920 /* Another port might have been enabled. Let's stop everything. */
5921 pause_proxy(p);
5922 break;
5923 }
5924 }
5925 }
5926 p = p->next;
5927 }
5928}
5929
5930
willy tarreau0f7af912005-12-17 12:21:26 +01005931/*
5932 * upon SIGUSR1, let's have a soft stop.
5933 */
5934void sig_soft_stop(int sig) {
5935 soft_stop();
5936 signal(sig, SIG_IGN);
5937}
5938
willy tarreaudbd3bef2006-01-20 19:35:18 +01005939/*
5940 * upon SIGTTOU, we pause everything
5941 */
5942void sig_pause(int sig) {
5943 pause_proxies();
5944 signal(sig, sig_pause);
5945}
willy tarreau0f7af912005-12-17 12:21:26 +01005946
willy tarreau8337c6b2005-12-17 13:41:01 +01005947/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01005948 * upon SIGTTIN, let's have a soft stop.
5949 */
5950void sig_listen(int sig) {
5951 listen_proxies();
5952 signal(sig, sig_listen);
5953}
5954
5955/*
willy tarreau8337c6b2005-12-17 13:41:01 +01005956 * this function dumps every server's state when the process receives SIGHUP.
5957 */
5958void sig_dump_state(int sig) {
5959 struct proxy *p = proxy;
5960
5961 Warning("SIGHUP received, dumping servers states.\n");
5962 while (p) {
5963 struct server *s = p->srv;
5964
5965 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
5966 while (s) {
5967 if (s->state & SRV_RUNNING) {
5968 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
5969 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
5970 }
5971 else {
5972 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5973 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5974 }
5975 s = s->next;
5976 }
willy tarreaudd07e972005-12-18 00:48:48 +01005977
5978 if (find_server(p) == NULL) {
5979 Warning("SIGHUP: proxy %s has no server available !\n", p);
5980 send_log(p, LOG_NOTICE, "SIGHUP: proxy %s has no server available !\n", p);
5981 }
5982
willy tarreau8337c6b2005-12-17 13:41:01 +01005983 p = p->next;
5984 }
5985 signal(sig, sig_dump_state);
5986}
5987
willy tarreau0f7af912005-12-17 12:21:26 +01005988void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005989 struct task *t, *tnext;
5990 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01005991
willy tarreau5cbea6f2005-12-17 12:48:26 +01005992 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5993 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5994 tnext = t->next;
5995 s = t->context;
5996 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
5997 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
5998 "req=%d, rep=%d, clifd=%d\n",
5999 s, tv_remain(&now, &t->expire),
6000 s->cli_state,
6001 s->srv_state,
6002 FD_ISSET(s->cli_fd, StaticReadEvent),
6003 FD_ISSET(s->cli_fd, StaticWriteEvent),
6004 FD_ISSET(s->srv_fd, StaticReadEvent),
6005 FD_ISSET(s->srv_fd, StaticWriteEvent),
6006 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6007 );
willy tarreau0f7af912005-12-17 12:21:26 +01006008 }
willy tarreau12350152005-12-18 01:03:27 +01006009}
6010
willy tarreau64a3cc32005-12-18 01:13:11 +01006011#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006012static void fast_stop(void)
6013{
6014 struct proxy *p;
6015 p = proxy;
6016 while (p) {
6017 p->grace = 0;
6018 p = p->next;
6019 }
6020 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006021}
6022
willy tarreau12350152005-12-18 01:03:27 +01006023void sig_int(int sig) {
6024 /* This would normally be a hard stop,
6025 but we want to be sure about deallocation,
6026 and so on, so we do a soft stop with
6027 0 GRACE time
6028 */
6029 fast_stop();
6030 /* If we are killed twice, we decide to die*/
6031 signal(sig, SIG_DFL);
6032}
6033
6034void sig_term(int sig) {
6035 /* This would normally be a hard stop,
6036 but we want to be sure about deallocation,
6037 and so on, so we do a soft stop with
6038 0 GRACE time
6039 */
6040 fast_stop();
6041 /* If we are killed twice, we decide to die*/
6042 signal(sig, SIG_DFL);
6043}
willy tarreau64a3cc32005-12-18 01:13:11 +01006044#endif
willy tarreau12350152005-12-18 01:03:27 +01006045
willy tarreauc1f47532005-12-18 01:08:26 +01006046/* returns the pointer to an error in the replacement string, or NULL if OK */
6047char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006048 struct hdr_exp *exp;
6049
willy tarreauc1f47532005-12-18 01:08:26 +01006050 if (replace != NULL) {
6051 char *err;
6052 err = check_replace_string(replace);
6053 if (err)
6054 return err;
6055 }
6056
willy tarreaue39cd132005-12-17 13:00:18 +01006057 while (*head != NULL)
6058 head = &(*head)->next;
6059
6060 exp = calloc(1, sizeof(struct hdr_exp));
6061
6062 exp->preg = preg;
6063 exp->replace = replace;
6064 exp->action = action;
6065 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006066
6067 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006068}
6069
willy tarreau9fe663a2005-12-17 13:02:59 +01006070
willy tarreau0f7af912005-12-17 12:21:26 +01006071/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006072 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006073 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006074int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006075
willy tarreau9fe663a2005-12-17 13:02:59 +01006076 if (!strcmp(args[0], "global")) { /* new section */
6077 /* no option, nothing special to do */
6078 return 0;
6079 }
6080 else if (!strcmp(args[0], "daemon")) {
6081 global.mode |= MODE_DAEMON;
6082 }
6083 else if (!strcmp(args[0], "debug")) {
6084 global.mode |= MODE_DEBUG;
6085 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006086 else if (!strcmp(args[0], "noepoll")) {
6087 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6088 }
6089 else if (!strcmp(args[0], "nopoll")) {
6090 cfg_polling_mechanism &= ~POLL_USE_POLL;
6091 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006092 else if (!strcmp(args[0], "quiet")) {
6093 global.mode |= MODE_QUIET;
6094 }
6095 else if (!strcmp(args[0], "stats")) {
6096 global.mode |= MODE_STATS;
6097 }
6098 else if (!strcmp(args[0], "uid")) {
6099 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006100 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006101 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006102 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006103 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006104 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006105 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006106 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006107 global.uid = atol(args[1]);
6108 }
6109 else if (!strcmp(args[0], "gid")) {
6110 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006111 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006112 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006113 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006114 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006115 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006116 return -1;
6117 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006118 global.gid = atol(args[1]);
6119 }
6120 else if (!strcmp(args[0], "nbproc")) {
6121 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006122 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006123 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006124 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006125 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006126 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006127 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006128 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006129 global.nbproc = atol(args[1]);
6130 }
6131 else if (!strcmp(args[0], "maxconn")) {
6132 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006133 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006134 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006135 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006136 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006137 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006138 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006139 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006140 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006141#ifdef SYSTEM_MAXCONN
6142 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6143 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);
6144 global.maxconn = DEFAULT_MAXCONN;
6145 }
6146#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006147 }
willy tarreaub1285d52005-12-18 01:20:14 +01006148 else if (!strcmp(args[0], "ulimit-n")) {
6149 if (global.rlimit_nofile != 0) {
6150 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6151 return 0;
6152 }
6153 if (*(args[1]) == 0) {
6154 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6155 return -1;
6156 }
6157 global.rlimit_nofile = atol(args[1]);
6158 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006159 else if (!strcmp(args[0], "chroot")) {
6160 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006161 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006162 return 0;
6163 }
6164 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006165 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006166 return -1;
6167 }
6168 global.chroot = strdup(args[1]);
6169 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006170 else if (!strcmp(args[0], "pidfile")) {
6171 if (global.pidfile != NULL) {
6172 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6173 return 0;
6174 }
6175 if (*(args[1]) == 0) {
6176 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6177 return -1;
6178 }
6179 global.pidfile = strdup(args[1]);
6180 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006181 else if (!strcmp(args[0], "log")) { /* syslog server address */
6182 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006183 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006184
6185 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006186 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006187 return -1;
6188 }
6189
6190 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6191 if (!strcmp(log_facilities[facility], args[2]))
6192 break;
6193
6194 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006195 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006196 exit(1);
6197 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006198
6199 level = 7; /* max syslog level = debug */
6200 if (*(args[3])) {
6201 while (level >= 0 && strcmp(log_levels[level], args[3]))
6202 level--;
6203 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006204 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006205 exit(1);
6206 }
6207 }
6208
willy tarreau9fe663a2005-12-17 13:02:59 +01006209 sa = str2sa(args[1]);
6210 if (!sa->sin_port)
6211 sa->sin_port = htons(SYSLOG_PORT);
6212
6213 if (global.logfac1 == -1) {
6214 global.logsrv1 = *sa;
6215 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006216 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006217 }
6218 else if (global.logfac2 == -1) {
6219 global.logsrv2 = *sa;
6220 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006221 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006222 }
6223 else {
6224 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6225 return -1;
6226 }
6227
6228 }
6229 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006230 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006231 return -1;
6232 }
6233 return 0;
6234}
6235
6236
willy tarreaua41a8b42005-12-17 14:02:24 +01006237void init_default_instance() {
6238 memset(&defproxy, 0, sizeof(defproxy));
6239 defproxy.mode = PR_MODE_TCP;
6240 defproxy.state = PR_STNEW;
6241 defproxy.maxconn = cfg_maxpconn;
6242 defproxy.conn_retries = CONN_RETRIES;
6243 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6244}
6245
willy tarreau9fe663a2005-12-17 13:02:59 +01006246/*
6247 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6248 */
6249int cfg_parse_listen(char *file, int linenum, char **args) {
6250 static struct proxy *curproxy = NULL;
6251 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006252 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006253 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006254
6255 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006256 if (!*args[1]) {
6257 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6258 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006259 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006260 return -1;
6261 }
6262
6263 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006264 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006265 return -1;
6266 }
6267 curproxy->next = proxy;
6268 proxy = curproxy;
6269 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006270
6271 /* parse the listener address if any */
6272 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006273 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006274 if (!curproxy->listen)
6275 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006276 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01006277 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006278
willy tarreau9fe663a2005-12-17 13:02:59 +01006279 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006280 curproxy->state = defproxy.state;
6281 curproxy->maxconn = defproxy.maxconn;
6282 curproxy->conn_retries = defproxy.conn_retries;
6283 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006284
6285 if (defproxy.check_req)
6286 curproxy->check_req = strdup(defproxy.check_req);
6287 curproxy->check_len = defproxy.check_len;
6288
6289 if (defproxy.cookie_name)
6290 curproxy->cookie_name = strdup(defproxy.cookie_name);
6291 curproxy->cookie_len = defproxy.cookie_len;
6292
6293 if (defproxy.capture_name)
6294 curproxy->capture_name = strdup(defproxy.capture_name);
6295 curproxy->capture_namelen = defproxy.capture_namelen;
6296 curproxy->capture_len = defproxy.capture_len;
6297
6298 if (defproxy.errmsg.msg400)
6299 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6300 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6301
6302 if (defproxy.errmsg.msg403)
6303 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6304 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6305
6306 if (defproxy.errmsg.msg408)
6307 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6308 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6309
6310 if (defproxy.errmsg.msg500)
6311 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6312 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6313
6314 if (defproxy.errmsg.msg502)
6315 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6316 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6317
6318 if (defproxy.errmsg.msg503)
6319 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6320 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6321
6322 if (defproxy.errmsg.msg504)
6323 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6324 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6325
willy tarreaua41a8b42005-12-17 14:02:24 +01006326 curproxy->clitimeout = defproxy.clitimeout;
6327 curproxy->contimeout = defproxy.contimeout;
6328 curproxy->srvtimeout = defproxy.srvtimeout;
6329 curproxy->mode = defproxy.mode;
6330 curproxy->logfac1 = defproxy.logfac1;
6331 curproxy->logsrv1 = defproxy.logsrv1;
6332 curproxy->loglev1 = defproxy.loglev1;
6333 curproxy->logfac2 = defproxy.logfac2;
6334 curproxy->logsrv2 = defproxy.logsrv2;
6335 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006336 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006337 curproxy->grace = defproxy.grace;
6338 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006339 curproxy->mon_net = defproxy.mon_net;
6340 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006341 return 0;
6342 }
6343 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006344 /* some variables may have already been initialized earlier */
6345 if (defproxy.check_req) free(defproxy.check_req);
6346 if (defproxy.cookie_name) free(defproxy.cookie_name);
6347 if (defproxy.capture_name) free(defproxy.capture_name);
6348 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6349 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6350 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6351 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6352 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6353 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6354 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6355
6356 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006357 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006358 return 0;
6359 }
6360 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006361 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006362 return -1;
6363 }
6364
willy tarreaua41a8b42005-12-17 14:02:24 +01006365 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6366 if (curproxy == &defproxy) {
6367 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6368 return -1;
6369 }
6370
6371 if (strchr(args[1], ':') == NULL) {
6372 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6373 file, linenum, args[0]);
6374 return -1;
6375 }
6376 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006377 if (!curproxy->listen)
6378 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006379 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006380 return 0;
6381 }
willy tarreaub1285d52005-12-18 01:20:14 +01006382 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6383 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6384 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6385 file, linenum, args[0]);
6386 return -1;
6387 }
6388 /* flush useless bits */
6389 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6390 return 0;
6391 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006392 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006393 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6394 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6395 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6396 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006397 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006398 return -1;
6399 }
6400 }
6401 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006402 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006403 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006404 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6405 curproxy->state = PR_STNEW;
6406 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006407 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6408 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006409// if (curproxy == &defproxy) {
6410// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6411// return -1;
6412// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006413
willy tarreau9fe663a2005-12-17 13:02:59 +01006414 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006415// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6416// file, linenum);
6417// return 0;
6418 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006419 }
6420
6421 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006422 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6423 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006424 return -1;
6425 }
6426 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006427 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006428
6429 cur_arg = 2;
6430 while (*(args[cur_arg])) {
6431 if (!strcmp(args[cur_arg], "rewrite")) {
6432 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006433 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006434 else if (!strcmp(args[cur_arg], "indirect")) {
6435 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006436 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006437 else if (!strcmp(args[cur_arg], "insert")) {
6438 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006439 }
willy tarreau240afa62005-12-17 13:14:35 +01006440 else if (!strcmp(args[cur_arg], "nocache")) {
6441 curproxy->options |= PR_O_COOK_NOC;
6442 }
willy tarreaucd878942005-12-17 13:27:43 +01006443 else if (!strcmp(args[cur_arg], "postonly")) {
6444 curproxy->options |= PR_O_COOK_POST;
6445 }
willy tarreau0174f312005-12-18 01:02:42 +01006446 else if (!strcmp(args[cur_arg], "prefix")) {
6447 curproxy->options |= PR_O_COOK_PFX;
6448 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006449 else {
willy tarreau0174f312005-12-18 01:02:42 +01006450 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006451 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006452 return -1;
6453 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006454 cur_arg++;
6455 }
willy tarreau0174f312005-12-18 01:02:42 +01006456 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6457 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6458 file, linenum);
6459 return -1;
6460 }
6461
6462 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6463 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006464 file, linenum);
6465 return -1;
6466 }
willy tarreau12350152005-12-18 01:03:27 +01006467 }/* end else if (!strcmp(args[0], "cookie")) */
6468 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6469// if (curproxy == &defproxy) {
6470// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6471// return -1;
6472// }
6473
6474 if (curproxy->appsession_name != NULL) {
6475// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6476// file, linenum);
6477// return 0;
6478 free(curproxy->appsession_name);
6479 }
6480
6481 if (*(args[5]) == 0) {
6482 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6483 file, linenum, args[0]);
6484 return -1;
6485 }
6486 have_appsession = 1;
6487 curproxy->appsession_name = strdup(args[1]);
6488 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6489 curproxy->appsession_len = atoi(args[3]);
6490 curproxy->appsession_timeout = atoi(args[5]);
6491 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6492 if (rc) {
6493 Alert("Error Init Appsession Hashtable.\n");
6494 return -1;
6495 }
6496 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006497 else if (!strcmp(args[0], "capture")) {
6498 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6499 // if (curproxy == &defproxy) {
6500 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6501 // return -1;
6502 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006503
willy tarreau4302f492005-12-18 01:00:37 +01006504 if (curproxy->capture_name != NULL) {
6505 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6506 // file, linenum, args[0]);
6507 // return 0;
6508 free(curproxy->capture_name);
6509 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006510
willy tarreau4302f492005-12-18 01:00:37 +01006511 if (*(args[4]) == 0) {
6512 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6513 file, linenum, args[0]);
6514 return -1;
6515 }
6516 curproxy->capture_name = strdup(args[2]);
6517 curproxy->capture_namelen = strlen(curproxy->capture_name);
6518 curproxy->capture_len = atol(args[4]);
6519 if (curproxy->capture_len >= CAPTURE_LEN) {
6520 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6521 file, linenum, CAPTURE_LEN - 1);
6522 curproxy->capture_len = CAPTURE_LEN - 1;
6523 }
6524 curproxy->to_log |= LW_COOKIE;
6525 }
6526 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6527 struct cap_hdr *hdr;
6528
6529 if (curproxy == &defproxy) {
6530 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6531 return -1;
6532 }
6533
6534 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6535 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6536 file, linenum, args[0], args[1]);
6537 return -1;
6538 }
6539
6540 hdr = calloc(sizeof(struct cap_hdr), 1);
6541 hdr->next = curproxy->req_cap;
6542 hdr->name = strdup(args[3]);
6543 hdr->namelen = strlen(args[3]);
6544 hdr->len = atol(args[5]);
6545 hdr->index = curproxy->nb_req_cap++;
6546 curproxy->req_cap = hdr;
6547 curproxy->to_log |= LW_REQHDR;
6548 }
6549 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6550 struct cap_hdr *hdr;
6551
6552 if (curproxy == &defproxy) {
6553 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6554 return -1;
6555 }
6556
6557 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6558 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6559 file, linenum, args[0], args[1]);
6560 return -1;
6561 }
6562 hdr = calloc(sizeof(struct cap_hdr), 1);
6563 hdr->next = curproxy->rsp_cap;
6564 hdr->name = strdup(args[3]);
6565 hdr->namelen = strlen(args[3]);
6566 hdr->len = atol(args[5]);
6567 hdr->index = curproxy->nb_rsp_cap++;
6568 curproxy->rsp_cap = hdr;
6569 curproxy->to_log |= LW_RSPHDR;
6570 }
6571 else {
6572 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006573 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006574 return -1;
6575 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006576 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006577 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006578 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006579 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006580 return 0;
6581 }
6582 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006583 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6584 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006585 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006586 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006587 curproxy->contimeout = atol(args[1]);
6588 }
6589 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006590 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006591 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6592 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006593 return 0;
6594 }
6595 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006596 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6597 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006598 return -1;
6599 }
6600 curproxy->clitimeout = atol(args[1]);
6601 }
6602 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006603 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006604 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006605 return 0;
6606 }
6607 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006608 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6609 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006610 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006611 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006612 curproxy->srvtimeout = atol(args[1]);
6613 }
6614 else if (!strcmp(args[0], "retries")) { /* connection retries */
6615 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006616 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6617 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006618 return -1;
6619 }
6620 curproxy->conn_retries = atol(args[1]);
6621 }
6622 else if (!strcmp(args[0], "option")) {
6623 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006624 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006625 return -1;
6626 }
6627 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006628 /* enable reconnections to dispatch */
6629 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006630#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006631 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006632 /* enable transparent proxy connections */
6633 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006634#endif
6635 else if (!strcmp(args[1], "keepalive"))
6636 /* enable keep-alive */
6637 curproxy->options |= PR_O_KEEPALIVE;
6638 else if (!strcmp(args[1], "forwardfor"))
6639 /* insert x-forwarded-for field */
6640 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006641 else if (!strcmp(args[1], "logasap"))
6642 /* log as soon as possible, without waiting for the session to complete */
6643 curproxy->options |= PR_O_LOGASAP;
6644 else if (!strcmp(args[1], "httpclose"))
6645 /* force connection: close in both directions in HTTP mode */
6646 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01006647 else if (!strcmp(args[1], "forceclose"))
6648 /* force connection: close in both directions in HTTP mode and enforce end of session */
6649 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006650 else if (!strcmp(args[1], "checkcache"))
6651 /* require examination of cacheability of the 'set-cookie' field */
6652 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006653 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006654 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006655 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006656 else if (!strcmp(args[1], "tcplog"))
6657 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006658 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006659 else if (!strcmp(args[1], "dontlognull")) {
6660 /* don't log empty requests */
6661 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006662 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006663 else if (!strcmp(args[1], "tcpka")) {
6664 /* enable TCP keep-alives on client and server sessions */
6665 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6666 }
6667 else if (!strcmp(args[1], "clitcpka")) {
6668 /* enable TCP keep-alives on client sessions */
6669 curproxy->options |= PR_O_TCP_CLI_KA;
6670 }
6671 else if (!strcmp(args[1], "srvtcpka")) {
6672 /* enable TCP keep-alives on server sessions */
6673 curproxy->options |= PR_O_TCP_SRV_KA;
6674 }
Willy TARREAU3481c462006-03-01 22:37:57 +01006675 else if (!strcmp(args[1], "allbackups")) {
6676 /* Use all backup servers simultaneously */
6677 curproxy->options |= PR_O_USE_ALL_BK;
6678 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006679 else if (!strcmp(args[1], "httpchk")) {
6680 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006681 if (curproxy->check_req != NULL) {
6682 free(curproxy->check_req);
6683 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006684 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006685 if (!*args[2]) { /* no argument */
6686 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6687 curproxy->check_len = strlen(DEF_CHECK_REQ);
6688 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006689 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6690 curproxy->check_req = (char *)malloc(reqlen);
6691 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6692 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006693 } else { /* more arguments : METHOD URI [HTTP_VER] */
6694 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6695 if (*args[4])
6696 reqlen += strlen(args[4]);
6697 else
6698 reqlen += strlen("HTTP/1.0");
6699
6700 curproxy->check_req = (char *)malloc(reqlen);
6701 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6702 "%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 +01006703 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006704 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006705 else if (!strcmp(args[1], "persist")) {
6706 /* persist on using the server specified by the cookie, even when it's down */
6707 curproxy->options |= PR_O_PERSIST;
6708 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006709 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006710 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006711 return -1;
6712 }
6713 return 0;
6714 }
6715 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6716 /* enable reconnections to dispatch */
6717 curproxy->options |= PR_O_REDISP;
6718 }
willy tarreaua1598082005-12-17 13:08:06 +01006719#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006720 else if (!strcmp(args[0], "transparent")) {
6721 /* enable transparent proxy connections */
6722 curproxy->options |= PR_O_TRANSP;
6723 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006724#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006725 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6726 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006727 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006728 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006729 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006730 curproxy->maxconn = atol(args[1]);
6731 }
6732 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6733 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006734 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006735 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006736 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006737 curproxy->grace = atol(args[1]);
6738 }
6739 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006740 if (curproxy == &defproxy) {
6741 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6742 return -1;
6743 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006744 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006745 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006746 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006747 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006748 curproxy->dispatch_addr = *str2sa(args[1]);
6749 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006750 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006751 if (*(args[1])) {
6752 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006753 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006754 }
6755 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006756 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006757 return -1;
6758 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006759 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006760 else /* if no option is set, use round-robin by default */
6761 curproxy->options |= PR_O_BALANCE_RR;
6762 }
6763 else if (!strcmp(args[0], "server")) { /* server address */
6764 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006765 char *rport;
6766 char *raddr;
6767 short realport;
6768 int do_check;
6769
6770 if (curproxy == &defproxy) {
6771 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6772 return -1;
6773 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006774
willy tarreaua41a8b42005-12-17 14:02:24 +01006775 if (!*args[2]) {
6776 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006777 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006778 return -1;
6779 }
6780 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6781 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6782 return -1;
6783 }
willy tarreau0174f312005-12-18 01:02:42 +01006784
6785 if (curproxy->srv == NULL)
6786 curproxy->srv = newsrv;
6787 else
6788 curproxy->cursrv->next = newsrv;
6789 curproxy->cursrv = newsrv;
6790
6791 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006792 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006793
6794 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006795 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006796 newsrv->id = strdup(args[1]);
6797
6798 /* several ways to check the port component :
6799 * - IP => port=+0, relative
6800 * - IP: => port=+0, relative
6801 * - IP:N => port=N, absolute
6802 * - IP:+N => port=+N, relative
6803 * - IP:-N => port=-N, relative
6804 */
6805 raddr = strdup(args[2]);
6806 rport = strchr(raddr, ':');
6807 if (rport) {
6808 *rport++ = 0;
6809 realport = atol(rport);
6810 if (!isdigit((int)*rport))
6811 newsrv->state |= SRV_MAPPORTS;
6812 } else {
6813 realport = 0;
6814 newsrv->state |= SRV_MAPPORTS;
6815 }
6816
6817 newsrv->addr = *str2sa(raddr);
6818 newsrv->addr.sin_port = htons(realport);
6819 free(raddr);
6820
willy tarreau9fe663a2005-12-17 13:02:59 +01006821 newsrv->curfd = -1; /* no health-check in progress */
6822 newsrv->inter = DEF_CHKINTR;
6823 newsrv->rise = DEF_RISETIME;
6824 newsrv->fall = DEF_FALLTIME;
6825 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
6826 cur_arg = 3;
6827 while (*args[cur_arg]) {
6828 if (!strcmp(args[cur_arg], "cookie")) {
6829 newsrv->cookie = strdup(args[cur_arg + 1]);
6830 newsrv->cklen = strlen(args[cur_arg + 1]);
6831 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006832 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006833 else if (!strcmp(args[cur_arg], "rise")) {
6834 newsrv->rise = atol(args[cur_arg + 1]);
6835 newsrv->health = newsrv->rise;
6836 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006837 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006838 else if (!strcmp(args[cur_arg], "fall")) {
6839 newsrv->fall = atol(args[cur_arg + 1]);
6840 cur_arg += 2;
6841 }
6842 else if (!strcmp(args[cur_arg], "inter")) {
6843 newsrv->inter = atol(args[cur_arg + 1]);
6844 cur_arg += 2;
6845 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006846 else if (!strcmp(args[cur_arg], "port")) {
6847 newsrv->check_port = atol(args[cur_arg + 1]);
6848 cur_arg += 2;
6849 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006850 else if (!strcmp(args[cur_arg], "backup")) {
6851 newsrv->state |= SRV_BACKUP;
6852 cur_arg ++;
6853 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006854 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01006855 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006856 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006857 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006858 }
willy tarreau0174f312005-12-18 01:02:42 +01006859 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
6860 if (!*args[cur_arg + 1]) {
6861 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
6862 file, linenum, "source");
6863 return -1;
6864 }
6865 newsrv->state |= SRV_BIND_SRC;
6866 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
6867 cur_arg += 2;
6868 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006869 else {
willy tarreau0174f312005-12-18 01:02:42 +01006870 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 +01006871 file, linenum, newsrv->id);
6872 return -1;
6873 }
6874 }
6875
6876 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006877 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
6878 newsrv->check_port = realport; /* by default */
6879 if (!newsrv->check_port) {
6880 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 +01006881 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006882 return -1;
6883 }
Willy TARREAU3759f982006-03-01 22:44:17 +01006884 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006885 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006886
willy tarreau9fe663a2005-12-17 13:02:59 +01006887 curproxy->nbservers++;
6888 }
6889 else if (!strcmp(args[0], "log")) { /* syslog server address */
6890 struct sockaddr_in *sa;
6891 int facility;
6892
6893 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
6894 curproxy->logfac1 = global.logfac1;
6895 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006896 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006897 curproxy->logfac2 = global.logfac2;
6898 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01006899 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01006900 }
6901 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01006902 int level;
6903
willy tarreau0f7af912005-12-17 12:21:26 +01006904 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6905 if (!strcmp(log_facilities[facility], args[2]))
6906 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01006907
willy tarreau0f7af912005-12-17 12:21:26 +01006908 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006909 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01006910 exit(1);
6911 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006912
willy tarreau8337c6b2005-12-17 13:41:01 +01006913 level = 7; /* max syslog level = debug */
6914 if (*(args[3])) {
6915 while (level >= 0 && strcmp(log_levels[level], args[3]))
6916 level--;
6917 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006918 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006919 exit(1);
6920 }
6921 }
6922
willy tarreau0f7af912005-12-17 12:21:26 +01006923 sa = str2sa(args[1]);
6924 if (!sa->sin_port)
6925 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01006926
willy tarreau0f7af912005-12-17 12:21:26 +01006927 if (curproxy->logfac1 == -1) {
6928 curproxy->logsrv1 = *sa;
6929 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006930 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006931 }
6932 else if (curproxy->logfac2 == -1) {
6933 curproxy->logsrv2 = *sa;
6934 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006935 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006936 }
6937 else {
6938 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006939 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006940 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006941 }
6942 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006943 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006944 file, linenum);
6945 return -1;
6946 }
6947 }
willy tarreaua1598082005-12-17 13:08:06 +01006948 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01006949 if (!*args[1]) {
6950 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006951 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01006952 return -1;
6953 }
6954
6955 curproxy->source_addr = *str2sa(args[1]);
6956 curproxy->options |= PR_O_BIND_SRC;
6957 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006958 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
6959 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006960 if (curproxy == &defproxy) {
6961 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6962 return -1;
6963 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006964
6965 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006966 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6967 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006968 return -1;
6969 }
6970
6971 preg = calloc(1, sizeof(regex_t));
6972 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006973 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006974 return -1;
6975 }
6976
willy tarreauc1f47532005-12-18 01:08:26 +01006977 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6978 if (err) {
6979 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6980 file, linenum, *err);
6981 return -1;
6982 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006983 }
6984 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
6985 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006986 if (curproxy == &defproxy) {
6987 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6988 return -1;
6989 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006990
6991 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006992 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006993 return -1;
6994 }
6995
6996 preg = calloc(1, sizeof(regex_t));
6997 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006998 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006999 return -1;
7000 }
7001
7002 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7003 }
7004 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7005 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007006 if (curproxy == &defproxy) {
7007 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7008 return -1;
7009 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007010
7011 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007012 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007013 return -1;
7014 }
7015
7016 preg = calloc(1, sizeof(regex_t));
7017 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007018 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007019 return -1;
7020 }
7021
7022 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7023 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007024 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7025 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007026 if (curproxy == &defproxy) {
7027 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7028 return -1;
7029 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007030
7031 if (*(args[1]) == 0) {
7032 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7033 return -1;
7034 }
7035
7036 preg = calloc(1, sizeof(regex_t));
7037 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7038 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7039 return -1;
7040 }
7041
7042 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7043 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007044 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7045 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007046 if (curproxy == &defproxy) {
7047 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7048 return -1;
7049 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007050
7051 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007052 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007053 return -1;
7054 }
7055
7056 preg = calloc(1, sizeof(regex_t));
7057 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007058 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007059 return -1;
7060 }
7061
7062 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7063 }
7064 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7065 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007066 if (curproxy == &defproxy) {
7067 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7068 return -1;
7069 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007070
7071 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007072 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7073 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007074 return -1;
7075 }
7076
7077 preg = calloc(1, sizeof(regex_t));
7078 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007079 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007080 return -1;
7081 }
7082
willy tarreauc1f47532005-12-18 01:08:26 +01007083 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7084 if (err) {
7085 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7086 file, linenum, *err);
7087 return -1;
7088 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007089 }
7090 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7091 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007092 if (curproxy == &defproxy) {
7093 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7094 return -1;
7095 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007096
7097 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007098 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007099 return -1;
7100 }
7101
7102 preg = calloc(1, sizeof(regex_t));
7103 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007104 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007105 return -1;
7106 }
7107
7108 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7109 }
7110 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7111 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007112 if (curproxy == &defproxy) {
7113 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7114 return -1;
7115 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007116
7117 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007118 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007119 return -1;
7120 }
7121
7122 preg = calloc(1, sizeof(regex_t));
7123 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007124 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007125 return -1;
7126 }
7127
7128 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7129 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007130 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7131 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007132 if (curproxy == &defproxy) {
7133 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7134 return -1;
7135 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007136
7137 if (*(args[1]) == 0) {
7138 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7139 return -1;
7140 }
7141
7142 preg = calloc(1, sizeof(regex_t));
7143 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7144 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7145 return -1;
7146 }
7147
7148 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7149 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007150 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7151 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007152 if (curproxy == &defproxy) {
7153 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7154 return -1;
7155 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007156
7157 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007158 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007159 return -1;
7160 }
7161
7162 preg = calloc(1, sizeof(regex_t));
7163 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007164 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007165 return -1;
7166 }
7167
7168 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7169 }
7170 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007171 if (curproxy == &defproxy) {
7172 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7173 return -1;
7174 }
7175
willy tarreau9fe663a2005-12-17 13:02:59 +01007176 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007177 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007178 return 0;
7179 }
7180
7181 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007182 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007183 return -1;
7184 }
7185
willy tarreau4302f492005-12-18 01:00:37 +01007186 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7187 }
7188 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7189 regex_t *preg;
7190
7191 if (*(args[1]) == 0 || *(args[2]) == 0) {
7192 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7193 file, linenum, args[0]);
7194 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007195 }
willy tarreau4302f492005-12-18 01:00:37 +01007196
7197 preg = calloc(1, sizeof(regex_t));
7198 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7199 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7200 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007201 }
willy tarreau4302f492005-12-18 01:00:37 +01007202
willy tarreauc1f47532005-12-18 01:08:26 +01007203 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7204 if (err) {
7205 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7206 file, linenum, *err);
7207 return -1;
7208 }
willy tarreau4302f492005-12-18 01:00:37 +01007209 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007210 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7211 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007212 if (curproxy == &defproxy) {
7213 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7214 return -1;
7215 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007216
7217 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007218 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007219 return -1;
7220 }
willy tarreaue39cd132005-12-17 13:00:18 +01007221
willy tarreau9fe663a2005-12-17 13:02:59 +01007222 preg = calloc(1, sizeof(regex_t));
7223 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007224 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007225 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007226 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007227
willy tarreauc1f47532005-12-18 01:08:26 +01007228 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7229 if (err) {
7230 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7231 file, linenum, *err);
7232 return -1;
7233 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007234 }
willy tarreau982249e2005-12-18 00:57:06 +01007235 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7236 regex_t *preg;
7237 if (curproxy == &defproxy) {
7238 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7239 return -1;
7240 }
7241
7242 if (*(args[1]) == 0) {
7243 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7244 return -1;
7245 }
7246
7247 preg = calloc(1, sizeof(regex_t));
7248 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7249 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7250 return -1;
7251 }
7252
willy tarreauc1f47532005-12-18 01:08:26 +01007253 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7254 if (err) {
7255 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7256 file, linenum, *err);
7257 return -1;
7258 }
willy tarreau982249e2005-12-18 00:57:06 +01007259 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007260 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007261 regex_t *preg;
7262 if (curproxy == &defproxy) {
7263 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7264 return -1;
7265 }
willy tarreaue39cd132005-12-17 13:00:18 +01007266
willy tarreaua41a8b42005-12-17 14:02:24 +01007267 if (*(args[1]) == 0 || *(args[2]) == 0) {
7268 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7269 file, linenum, args[0]);
7270 return -1;
7271 }
willy tarreaue39cd132005-12-17 13:00:18 +01007272
willy tarreaua41a8b42005-12-17 14:02:24 +01007273 preg = calloc(1, sizeof(regex_t));
7274 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7275 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7276 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007277 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007278
willy tarreauc1f47532005-12-18 01:08:26 +01007279 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7280 if (err) {
7281 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7282 file, linenum, *err);
7283 return -1;
7284 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007285 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007286 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7287 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007288 if (curproxy == &defproxy) {
7289 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7290 return -1;
7291 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007292
7293 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007294 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007295 return -1;
7296 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007297
willy tarreau9fe663a2005-12-17 13:02:59 +01007298 preg = calloc(1, sizeof(regex_t));
7299 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007300 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007301 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007302 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007303
willy tarreauc1f47532005-12-18 01:08:26 +01007304 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7305 if (err) {
7306 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7307 file, linenum, *err);
7308 return -1;
7309 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007310 }
willy tarreau982249e2005-12-18 00:57:06 +01007311 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7312 regex_t *preg;
7313 if (curproxy == &defproxy) {
7314 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7315 return -1;
7316 }
7317
7318 if (*(args[1]) == 0) {
7319 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7320 return -1;
7321 }
7322
7323 preg = calloc(1, sizeof(regex_t));
7324 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7325 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7326 return -1;
7327 }
7328
willy tarreauc1f47532005-12-18 01:08:26 +01007329 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7330 if (err) {
7331 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7332 file, linenum, *err);
7333 return -1;
7334 }
willy tarreau982249e2005-12-18 00:57:06 +01007335 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007336 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007337 if (curproxy == &defproxy) {
7338 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7339 return -1;
7340 }
7341
willy tarreau9fe663a2005-12-17 13:02:59 +01007342 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007343 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007344 return 0;
7345 }
7346
7347 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007348 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007349 return -1;
7350 }
7351
7352 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7353 }
willy tarreauc1f47532005-12-18 01:08:26 +01007354 else if (!strcmp(args[0], "errorloc") ||
7355 !strcmp(args[0], "errorloc302") ||
7356 !strcmp(args[0], "errorloc303")) { /* error location */
7357 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007358 char *err;
7359
willy tarreaueedaa9f2005-12-17 14:08:03 +01007360 // if (curproxy == &defproxy) {
7361 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7362 // return -1;
7363 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007364
willy tarreau8337c6b2005-12-17 13:41:01 +01007365 if (*(args[2]) == 0) {
7366 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7367 return -1;
7368 }
7369
7370 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007371 if (!strcmp(args[0], "errorloc303")) {
7372 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7373 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7374 } else {
7375 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7376 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7377 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007378
7379 if (errnum == 400) {
7380 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007381 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007382 free(curproxy->errmsg.msg400);
7383 }
7384 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007385 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007386 }
7387 else if (errnum == 403) {
7388 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007389 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007390 free(curproxy->errmsg.msg403);
7391 }
7392 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007393 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007394 }
7395 else if (errnum == 408) {
7396 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007397 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007398 free(curproxy->errmsg.msg408);
7399 }
7400 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007401 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007402 }
7403 else if (errnum == 500) {
7404 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007405 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007406 free(curproxy->errmsg.msg500);
7407 }
7408 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007409 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007410 }
7411 else if (errnum == 502) {
7412 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007413 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007414 free(curproxy->errmsg.msg502);
7415 }
7416 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007417 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007418 }
7419 else if (errnum == 503) {
7420 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007421 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007422 free(curproxy->errmsg.msg503);
7423 }
7424 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007425 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007426 }
7427 else if (errnum == 504) {
7428 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007429 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007430 free(curproxy->errmsg.msg504);
7431 }
7432 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007433 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007434 }
7435 else {
7436 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7437 free(err);
7438 }
7439 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007440 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007441 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007442 return -1;
7443 }
7444 return 0;
7445}
willy tarreaue39cd132005-12-17 13:00:18 +01007446
willy tarreau5cbea6f2005-12-17 12:48:26 +01007447
willy tarreau9fe663a2005-12-17 13:02:59 +01007448/*
7449 * This function reads and parses the configuration file given in the argument.
7450 * returns 0 if OK, -1 if error.
7451 */
7452int readcfgfile(char *file) {
7453 char thisline[256];
7454 char *line;
7455 FILE *f;
7456 int linenum = 0;
7457 char *end;
7458 char *args[MAX_LINE_ARGS];
7459 int arg;
7460 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007461 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007462 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007463
willy tarreau9fe663a2005-12-17 13:02:59 +01007464 struct proxy *curproxy = NULL;
7465 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007466
willy tarreau9fe663a2005-12-17 13:02:59 +01007467 if ((f=fopen(file,"r")) == NULL)
7468 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007469
willy tarreaueedaa9f2005-12-17 14:08:03 +01007470 init_default_instance();
7471
willy tarreau9fe663a2005-12-17 13:02:59 +01007472 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7473 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007474
willy tarreau9fe663a2005-12-17 13:02:59 +01007475 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007476
willy tarreau9fe663a2005-12-17 13:02:59 +01007477 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007478 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007479 line++;
7480
7481 arg = 0;
7482 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007483
willy tarreau9fe663a2005-12-17 13:02:59 +01007484 while (*line && arg < MAX_LINE_ARGS) {
7485 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7486 * C equivalent value. Other combinations left unchanged (eg: \1).
7487 */
7488 if (*line == '\\') {
7489 int skip = 0;
7490 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7491 *line = line[1];
7492 skip = 1;
7493 }
7494 else if (line[1] == 'r') {
7495 *line = '\r';
7496 skip = 1;
7497 }
7498 else if (line[1] == 'n') {
7499 *line = '\n';
7500 skip = 1;
7501 }
7502 else if (line[1] == 't') {
7503 *line = '\t';
7504 skip = 1;
7505 }
willy tarreauc1f47532005-12-18 01:08:26 +01007506 else if (line[1] == 'x') {
7507 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7508 unsigned char hex1, hex2;
7509 hex1 = toupper(line[2]) - '0';
7510 hex2 = toupper(line[3]) - '0';
7511 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7512 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7513 *line = (hex1<<4) + hex2;
7514 skip = 3;
7515 }
7516 else {
7517 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7518 return -1;
7519 }
7520 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007521 if (skip) {
7522 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7523 end -= skip;
7524 }
7525 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007526 }
willy tarreaua1598082005-12-17 13:08:06 +01007527 else if (*line == '#' || *line == '\n' || *line == '\r') {
7528 /* end of string, end of loop */
7529 *line = 0;
7530 break;
7531 }
willy tarreauc29948c2005-12-17 13:10:27 +01007532 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007533 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007534 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007535 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007536 line++;
7537 args[++arg] = line;
7538 }
7539 else {
7540 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007541 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007542 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007543
willy tarreau9fe663a2005-12-17 13:02:59 +01007544 /* empty line */
7545 if (!**args)
7546 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007547
willy tarreau9fe663a2005-12-17 13:02:59 +01007548 /* zero out remaining args */
7549 while (++arg < MAX_LINE_ARGS) {
7550 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007551 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007552
willy tarreaua41a8b42005-12-17 14:02:24 +01007553 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007554 confsect = CFG_LISTEN;
7555 else if (!strcmp(args[0], "global")) /* global config */
7556 confsect = CFG_GLOBAL;
7557 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007558
willy tarreau9fe663a2005-12-17 13:02:59 +01007559 switch (confsect) {
7560 case CFG_LISTEN:
7561 if (cfg_parse_listen(file, linenum, args) < 0)
7562 return -1;
7563 break;
7564 case CFG_GLOBAL:
7565 if (cfg_parse_global(file, linenum, args) < 0)
7566 return -1;
7567 break;
7568 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007569 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007570 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007571 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007572
7573
willy tarreau0f7af912005-12-17 12:21:26 +01007574 }
7575 fclose(f);
7576
7577 /*
7578 * Now, check for the integrity of all that we have collected.
7579 */
7580
Willy TARREAU3759f982006-03-01 22:44:17 +01007581 /* will be needed further to delay some tasks */
7582 tv_now(&now);
7583
willy tarreau0f7af912005-12-17 12:21:26 +01007584 if ((curproxy = proxy) == NULL) {
7585 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7586 file);
7587 return -1;
7588 }
7589
7590 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007591 curproxy->cursrv = NULL;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007592 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007593 curproxy = curproxy->next;
7594 continue;
7595 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007596
7597 if (curproxy->listen == NULL) {
7598 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);
7599 cfgerr++;
7600 }
7601 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007602 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007603 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007604 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7605 file, curproxy->id);
7606 cfgerr++;
7607 }
7608 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7609 if (curproxy->options & PR_O_TRANSP) {
7610 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7611 file, curproxy->id);
7612 cfgerr++;
7613 }
7614 else if (curproxy->srv == NULL) {
7615 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7616 file, curproxy->id);
7617 cfgerr++;
7618 }
willy tarreaua1598082005-12-17 13:08:06 +01007619 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007620 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7621 file, curproxy->id);
7622 }
7623 }
7624 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007625 if (curproxy->cookie_name != NULL) {
7626 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7627 file, curproxy->id);
7628 }
7629 if ((newsrv = curproxy->srv) != NULL) {
7630 Warning("parsing %s : servers will be ignored for listener %s.\n",
7631 file, curproxy->id);
7632 }
willy tarreaue39cd132005-12-17 13:00:18 +01007633 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007634 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7635 file, curproxy->id);
7636 }
willy tarreaue39cd132005-12-17 13:00:18 +01007637 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007638 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7639 file, curproxy->id);
7640 }
7641 }
7642 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7643 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7644 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7645 file, curproxy->id);
7646 cfgerr++;
7647 }
7648 else {
7649 while (newsrv != NULL) {
7650 /* nothing to check for now */
7651 newsrv = newsrv->next;
7652 }
7653 }
7654 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007655
7656 if (curproxy->options & PR_O_LOGASAP)
7657 curproxy->to_log &= ~LW_BYTES;
7658
willy tarreau8337c6b2005-12-17 13:41:01 +01007659 if (curproxy->errmsg.msg400 == NULL) {
7660 curproxy->errmsg.msg400 = (char *)HTTP_400;
7661 curproxy->errmsg.len400 = strlen(HTTP_400);
7662 }
7663 if (curproxy->errmsg.msg403 == NULL) {
7664 curproxy->errmsg.msg403 = (char *)HTTP_403;
7665 curproxy->errmsg.len403 = strlen(HTTP_403);
7666 }
7667 if (curproxy->errmsg.msg408 == NULL) {
7668 curproxy->errmsg.msg408 = (char *)HTTP_408;
7669 curproxy->errmsg.len408 = strlen(HTTP_408);
7670 }
7671 if (curproxy->errmsg.msg500 == NULL) {
7672 curproxy->errmsg.msg500 = (char *)HTTP_500;
7673 curproxy->errmsg.len500 = strlen(HTTP_500);
7674 }
7675 if (curproxy->errmsg.msg502 == NULL) {
7676 curproxy->errmsg.msg502 = (char *)HTTP_502;
7677 curproxy->errmsg.len502 = strlen(HTTP_502);
7678 }
7679 if (curproxy->errmsg.msg503 == NULL) {
7680 curproxy->errmsg.msg503 = (char *)HTTP_503;
7681 curproxy->errmsg.len503 = strlen(HTTP_503);
7682 }
7683 if (curproxy->errmsg.msg504 == NULL) {
7684 curproxy->errmsg.msg504 = (char *)HTTP_504;
7685 curproxy->errmsg.len504 = strlen(HTTP_504);
7686 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007687
7688 /* now we'll start this proxy's health checks if any */
7689 /* 1- count the checkers to run simultaneously */
7690 nbchk = 0;
7691 mininter = 0;
7692 newsrv = curproxy->srv;
7693 while (newsrv != NULL) {
7694 if (newsrv->state & SRV_CHECKED) {
7695 if (!mininter || mininter > newsrv->inter)
7696 mininter = newsrv->inter;
7697 nbchk++;
7698 }
7699 newsrv = newsrv->next;
7700 }
7701
7702 /* 2- start them as far as possible from each others while respecting
7703 * their own intervals. For this, we will start them after their own
7704 * interval added to the min interval divided by the number of servers,
7705 * weighted by the server's position in the list.
7706 */
7707 if (nbchk > 0) {
7708 struct task *t;
7709 int srvpos;
7710
7711 newsrv = curproxy->srv;
7712 srvpos = 0;
7713 while (newsrv != NULL) {
7714 /* should this server be checked ? */
7715 if (newsrv->state & SRV_CHECKED) {
7716 if ((t = pool_alloc(task)) == NULL) {
7717 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7718 return -1;
7719 }
7720
7721 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
7722 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
7723 t->state = TASK_IDLE;
7724 t->process = process_chk;
7725 t->context = newsrv;
7726
7727 /* check this every ms */
7728 tv_delayfrom(&t->expire, &now,
7729 newsrv->inter + mininter * srvpos / nbchk);
7730 task_queue(t);
7731 //task_wakeup(&rq, t);
7732 srvpos++;
7733 }
7734 newsrv = newsrv->next;
7735 }
7736 }
7737
willy tarreau0f7af912005-12-17 12:21:26 +01007738 curproxy = curproxy->next;
7739 }
7740 if (cfgerr > 0) {
7741 Alert("Errors found in configuration file, aborting.\n");
7742 return -1;
7743 }
7744 else
7745 return 0;
7746}
7747
7748
7749/*
7750 * This function initializes all the necessary variables. It only returns
7751 * if everything is OK. If something fails, it exits.
7752 */
7753void init(int argc, char **argv) {
7754 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007755 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007756 char *old_argv = *argv;
7757 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007758 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007759
7760 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007761 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007762 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007763 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007764 exit(1);
7765 }
7766
Willy TARREAUa9e75f62006-03-01 22:27:48 +01007767 /* initialize the libc's localtime structures once for all so that we
7768 * won't be missing memory if we want to send alerts under OOM conditions.
7769 */
7770 tv_now(&now);
7771 localtime(&now.tv_sec);
7772
willy tarreau4302f492005-12-18 01:00:37 +01007773 /* initialize the log header encoding map : '{|}"#' should be encoded with
7774 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7775 * URL encoding only requires '"', '#' to be encoded as well as non-
7776 * printable characters above.
7777 */
7778 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7779 memset(url_encode_map, 0, sizeof(url_encode_map));
7780 for (i = 0; i < 32; i++) {
7781 FD_SET(i, hdr_encode_map);
7782 FD_SET(i, url_encode_map);
7783 }
7784 for (i = 127; i < 256; i++) {
7785 FD_SET(i, hdr_encode_map);
7786 FD_SET(i, url_encode_map);
7787 }
7788
7789 tmp = "\"#{|}";
7790 while (*tmp) {
7791 FD_SET(*tmp, hdr_encode_map);
7792 tmp++;
7793 }
7794
7795 tmp = "\"#";
7796 while (*tmp) {
7797 FD_SET(*tmp, url_encode_map);
7798 tmp++;
7799 }
7800
willy tarreau64a3cc32005-12-18 01:13:11 +01007801 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
7802#if defined(ENABLE_POLL)
7803 cfg_polling_mechanism |= POLL_USE_POLL;
7804#endif
7805#if defined(ENABLE_EPOLL)
7806 cfg_polling_mechanism |= POLL_USE_EPOLL;
7807#endif
7808
willy tarreau0f7af912005-12-17 12:21:26 +01007809 pid = getpid();
7810 progname = *argv;
7811 while ((tmp = strchr(progname, '/')) != NULL)
7812 progname = tmp + 1;
7813
7814 argc--; argv++;
7815 while (argc > 0) {
7816 char *flag;
7817
7818 if (**argv == '-') {
7819 flag = *argv+1;
7820
7821 /* 1 arg */
7822 if (*flag == 'v') {
7823 display_version();
7824 exit(0);
7825 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007826#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007827 else if (*flag == 'd' && flag[1] == 'e')
7828 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007829#endif
7830#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007831 else if (*flag == 'd' && flag[1] == 'p')
7832 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007833#endif
willy tarreau982249e2005-12-18 00:57:06 +01007834 else if (*flag == 'V')
7835 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01007836 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01007837 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01007838 else if (*flag == 'c')
7839 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01007840 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01007841 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007842 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01007843 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01007844#if STATTIME > 0
7845 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01007846 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01007847 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01007848 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01007849#endif
7850 else { /* >=2 args */
7851 argv++; argc--;
7852 if (argc == 0)
7853 usage(old_argv);
7854
7855 switch (*flag) {
7856 case 'n' : cfg_maxconn = atol(*argv); break;
7857 case 'N' : cfg_maxpconn = atol(*argv); break;
7858 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007859 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01007860 default: usage(old_argv);
7861 }
7862 }
7863 }
7864 else
7865 usage(old_argv);
7866 argv++; argc--;
7867 }
7868
willy tarreaud0fb4652005-12-18 01:32:04 +01007869 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
7870 (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01007871
willy tarreau0f7af912005-12-17 12:21:26 +01007872 if (!cfg_cfgfile)
7873 usage(old_argv);
7874
7875 gethostname(hostname, MAX_HOSTNAME_LEN);
7876
willy tarreau12350152005-12-18 01:03:27 +01007877 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007878 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01007879 if (readcfgfile(cfg_cfgfile) < 0) {
7880 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
7881 exit(1);
7882 }
willy tarreau12350152005-12-18 01:03:27 +01007883 if (have_appsession)
7884 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01007885
willy tarreau982249e2005-12-18 00:57:06 +01007886 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01007887 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
7888 exit(0);
7889 }
7890
willy tarreau9fe663a2005-12-17 13:02:59 +01007891 if (cfg_maxconn > 0)
7892 global.maxconn = cfg_maxconn;
7893
willy tarreaufe2c5c12005-12-17 14:14:34 +01007894 if (cfg_pidfile) {
7895 if (global.pidfile)
7896 free(global.pidfile);
7897 global.pidfile = strdup(cfg_pidfile);
7898 }
7899
willy tarreau9fe663a2005-12-17 13:02:59 +01007900 if (global.maxconn == 0)
7901 global.maxconn = DEFAULT_MAXCONN;
7902
Willy TARREAU203b0b62006-03-12 18:00:28 +01007903 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01007904
7905 if (arg_mode & MODE_DEBUG) {
7906 /* command line debug mode inhibits configuration mode */
7907 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7908 }
willy tarreau982249e2005-12-18 00:57:06 +01007909 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
7910 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01007911
7912 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
7913 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
7914 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7915 }
7916
7917 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
7918 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
7919 global.nbproc = 1;
7920 }
7921
7922 if (global.nbproc < 1)
7923 global.nbproc = 1;
7924
willy tarreau0f7af912005-12-17 12:21:26 +01007925 StaticReadEvent = (fd_set *)calloc(1,
7926 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007927 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007928 StaticWriteEvent = (fd_set *)calloc(1,
7929 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007930 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007931
7932 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01007933 sizeof(struct fdtab) * (global.maxsock));
7934 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01007935 fdtab[i].state = FD_STCLOSE;
7936 }
7937}
7938
7939/*
7940 * this function starts all the proxies. It returns 0 if OK, -1 if not.
7941 */
7942int start_proxies() {
7943 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007944 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01007945 int fd;
7946
7947 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007948 if (curproxy->state == PR_STSTOPPED)
willy tarreau0f7af912005-12-17 12:21:26 +01007949 continue;
7950
willy tarreaua41a8b42005-12-17 14:02:24 +01007951 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
7952 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01007953 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007954 Alert("cannot create listening socket for proxy %s. Aborting.\n",
7955 curproxy->id);
7956 return -1;
7957 }
willy tarreau0f7af912005-12-17 12:21:26 +01007958
willy tarreaua41a8b42005-12-17 14:02:24 +01007959 if (fd >= global.maxsock) {
7960 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
7961 curproxy->id);
7962 close(fd);
7963 return -1;
7964 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007965
willy tarreaua41a8b42005-12-17 14:02:24 +01007966 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
7967 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
7968 (char *) &one, sizeof(one)) == -1)) {
7969 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
7970 curproxy->id);
7971 close(fd);
7972 return -1;
7973 }
willy tarreau0f7af912005-12-17 12:21:26 +01007974
willy tarreaua41a8b42005-12-17 14:02:24 +01007975 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
7976 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
7977 curproxy->id);
7978 }
willy tarreau0f7af912005-12-17 12:21:26 +01007979
willy tarreaua41a8b42005-12-17 14:02:24 +01007980 if (bind(fd,
7981 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01007982 listener->addr.ss_family == AF_INET6 ?
7983 sizeof(struct sockaddr_in6) :
7984 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007985 Alert("cannot bind socket for proxy %s. Aborting.\n",
7986 curproxy->id);
7987 close(fd);
7988 return -1;
7989 }
willy tarreau0f7af912005-12-17 12:21:26 +01007990
willy tarreaua41a8b42005-12-17 14:02:24 +01007991 if (listen(fd, curproxy->maxconn) == -1) {
7992 Alert("cannot listen to socket for proxy %s. Aborting.\n",
7993 curproxy->id);
7994 close(fd);
7995 return -1;
7996 }
willy tarreau0f7af912005-12-17 12:21:26 +01007997
willy tarreaua41a8b42005-12-17 14:02:24 +01007998 /* the function for the accept() event */
7999 fdtab[fd].read = &event_accept;
8000 fdtab[fd].write = NULL; /* never called */
8001 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
8002 curproxy->state = PR_STRUN;
8003 fdtab[fd].state = FD_STLISTEN;
8004 FD_SET(fd, StaticReadEvent);
8005 fd_insert(fd);
8006 listeners++;
8007 }
willy tarreaua1598082005-12-17 13:08:06 +01008008 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01008009 }
8010 return 0;
8011}
8012
willy tarreaub952e1d2005-12-18 01:31:20 +01008013int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008014
8015 appsess *temp1,*temp2;
8016 temp1 = (appsess *)key1;
8017 temp2 = (appsess *)key2;
8018
8019 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8020 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8021
8022 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8023}/* end match_str */
8024
willy tarreaub952e1d2005-12-18 01:31:20 +01008025void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008026 appsess *temp1;
8027
8028 //printf("destroy called\n");
8029 temp1 = (appsess *)data;
8030
8031 if (temp1->sessid)
8032 pool_free_to(apools.sessid, temp1->sessid);
8033
8034 if (temp1->serverid)
8035 pool_free_to(apools.serverid, temp1->serverid);
8036
8037 pool_free(appsess, temp1);
8038} /* end destroy */
8039
8040void appsession_cleanup( void )
8041{
8042 struct proxy *p = proxy;
8043
8044 while(p) {
8045 chtbl_destroy(&(p->htbl_proxy));
8046 p = p->next;
8047 }
8048}/* end appsession_cleanup() */
8049
8050void pool_destroy(void **pool)
8051{
8052 void *temp, *next;
8053 next = pool;
8054 while (next) {
8055 temp = next;
8056 next = *(void **)temp;
8057 free(temp);
8058 }
8059}/* end pool_destroy() */
8060
willy tarreaub952e1d2005-12-18 01:31:20 +01008061void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008062 struct proxy *p = proxy;
8063 struct cap_hdr *h,*h_next;
8064 struct server *s,*s_next;
8065 struct listener *l,*l_next;
8066
8067 while (p) {
8068 if (p->id)
8069 free(p->id);
8070
8071 if (p->check_req)
8072 free(p->check_req);
8073
8074 if (p->cookie_name)
8075 free(p->cookie_name);
8076
8077 if (p->capture_name)
8078 free(p->capture_name);
8079
8080 /* only strup if the user have set in config.
8081 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008082 if (p->errmsg.msg400) free(p->errmsg.msg400);
8083 if (p->errmsg.msg403) free(p->errmsg.msg403);
8084 if (p->errmsg.msg408) free(p->errmsg.msg408);
8085 if (p->errmsg.msg500) free(p->errmsg.msg500);
8086 if (p->errmsg.msg502) free(p->errmsg.msg502);
8087 if (p->errmsg.msg503) free(p->errmsg.msg503);
8088 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008089 */
8090 if (p->appsession_name)
8091 free(p->appsession_name);
8092
8093 h = p->req_cap;
8094 while (h) {
8095 h_next = h->next;
8096 if (h->name)
8097 free(h->name);
8098 pool_destroy(h->pool);
8099 free(h);
8100 h = h_next;
8101 }/* end while(h) */
8102
8103 h = p->rsp_cap;
8104 while (h) {
8105 h_next = h->next;
8106 if (h->name)
8107 free(h->name);
8108
8109 pool_destroy(h->pool);
8110 free(h);
8111 h = h_next;
8112 }/* end while(h) */
8113
8114 s = p->srv;
8115 while (s) {
8116 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008117 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008118 free(s->id);
8119
willy tarreaub952e1d2005-12-18 01:31:20 +01008120 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008121 free(s->cookie);
8122
8123 free(s);
8124 s = s_next;
8125 }/* end while(s) */
8126
8127 l = p->listen;
8128 while (l) {
8129 l_next = l->next;
8130 free(l);
8131 l = l_next;
8132 }/* end while(l) */
8133
8134 pool_destroy((void **) p->req_cap_pool);
8135 pool_destroy((void **) p->rsp_cap_pool);
8136 p = p->next;
8137 }/* end while(p) */
8138
8139 if (global.chroot) free(global.chroot);
8140 if (global.pidfile) free(global.pidfile);
8141
willy tarreau12350152005-12-18 01:03:27 +01008142 if (StaticReadEvent) free(StaticReadEvent);
8143 if (StaticWriteEvent) free(StaticWriteEvent);
8144 if (fdtab) free(fdtab);
8145
8146 pool_destroy(pool_session);
8147 pool_destroy(pool_buffer);
8148 pool_destroy(pool_fdtab);
8149 pool_destroy(pool_requri);
8150 pool_destroy(pool_task);
8151 pool_destroy(pool_capture);
8152 pool_destroy(pool_appsess);
8153
8154 if (have_appsession) {
8155 pool_destroy(apools.serverid);
8156 pool_destroy(apools.sessid);
8157 }
8158} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008159
8160int main(int argc, char **argv) {
willy tarreaub1285d52005-12-18 01:20:14 +01008161 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008162 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008163 init(argc, argv);
8164
willy tarreau0f7af912005-12-17 12:21:26 +01008165 signal(SIGQUIT, dump);
8166 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008167 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008168#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008169 signal(SIGINT, sig_int);
8170 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008171#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008172
8173 /* on very high loads, a sigpipe sometimes happen just between the
8174 * getsockopt() which tells "it's OK to write", and the following write :-(
8175 */
willy tarreau3242e862005-12-17 12:27:53 +01008176#ifndef MSG_NOSIGNAL
8177 signal(SIGPIPE, SIG_IGN);
8178#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008179
willy tarreaud0fb4652005-12-18 01:32:04 +01008180 /* start_proxies() sends an alert when it fails. */
willy tarreau0f7af912005-12-17 12:21:26 +01008181 if (start_proxies() < 0)
8182 exit(1);
willy tarreaud0fb4652005-12-18 01:32:04 +01008183
8184 if (listeners == 0) {
8185 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
8186 exit(1);
8187 }
8188
willy tarreaudbd3bef2006-01-20 19:35:18 +01008189 /* prepare pause/play signals */
8190 signal(SIGTTOU, sig_pause);
8191 signal(SIGTTIN, sig_listen);
8192
Willy TARREAUe3283d12006-03-01 22:15:29 +01008193 if (global.mode & MODE_DAEMON) {
8194 global.mode &= ~MODE_VERBOSE;
8195 global.mode |= MODE_QUIET;
8196 }
8197
willy tarreaud0fb4652005-12-18 01:32:04 +01008198 /* MODE_QUIET can inhibit alerts and warnings below this line */
8199
8200 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008201 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008202 /* detach from the tty */
8203 fclose(stdin); fclose(stdout); fclose(stderr);
8204 close(0); close(1); close(2);
8205 }
willy tarreau0f7af912005-12-17 12:21:26 +01008206
willy tarreaufe2c5c12005-12-17 14:14:34 +01008207 /* open log & pid files before the chroot */
8208 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8209 int pidfd;
8210 unlink(global.pidfile);
8211 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8212 if (pidfd < 0) {
8213 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
8214 exit(1);
8215 }
8216 pidfile = fdopen(pidfd, "w");
8217 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008218
8219 /* chroot if needed */
8220 if (global.chroot != NULL) {
8221 if (chroot(global.chroot) == -1) {
8222 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
8223 exit(1);
8224 }
8225 chdir("/");
8226 }
8227
willy tarreaub1285d52005-12-18 01:20:14 +01008228 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01008229 if (!global.rlimit_nofile)
8230 global.rlimit_nofile = global.maxsock;
8231
willy tarreaub1285d52005-12-18 01:20:14 +01008232 if (global.rlimit_nofile) {
8233 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8234 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8235 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8236 }
8237 }
8238
willy tarreau9fe663a2005-12-17 13:02:59 +01008239 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008240 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008241 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8242 exit(1);
8243 }
8244
willy tarreau036e1ce2005-12-17 13:46:33 +01008245 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008246 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8247 exit(1);
8248 }
8249
willy tarreaub1285d52005-12-18 01:20:14 +01008250 /* check ulimits */
8251 limit.rlim_cur = limit.rlim_max = 0;
8252 getrlimit(RLIMIT_NOFILE, &limit);
8253 if (limit.rlim_cur < global.maxsock) {
8254 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",
8255 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8256 }
8257
willy tarreau9fe663a2005-12-17 13:02:59 +01008258 if (global.mode & MODE_DAEMON) {
8259 int ret = 0;
8260 int proc;
8261
8262 /* the father launches the required number of processes */
8263 for (proc = 0; proc < global.nbproc; proc++) {
8264 ret = fork();
8265 if (ret < 0) {
8266 Alert("[%s.main()] Cannot fork.\n", argv[0]);
8267 exit(1); /* there has been an error */
8268 }
8269 else if (ret == 0) /* child breaks here */
8270 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008271 if (pidfile != NULL) {
8272 fprintf(pidfile, "%d\n", ret);
8273 fflush(pidfile);
8274 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008275 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008276 /* close the pidfile both in children and father */
8277 if (pidfile != NULL)
8278 fclose(pidfile);
8279 free(global.pidfile);
8280
willy tarreau9fe663a2005-12-17 13:02:59 +01008281 if (proc == global.nbproc)
8282 exit(0); /* parent must leave */
8283
willy tarreau750a4722005-12-17 13:21:24 +01008284 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8285 * that we can detach from the TTY. We MUST NOT do it in other cases since
8286 * it would have already be done, and 0-2 would have been affected to listening
8287 * sockets
8288 */
8289 if (!(global.mode & MODE_QUIET)) {
8290 /* detach from the tty */
8291 fclose(stdin); fclose(stdout); fclose(stderr);
8292 close(0); close(1); close(2); /* close all fd's */
8293 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8294 }
willy tarreaua1598082005-12-17 13:08:06 +01008295 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008296 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008297 }
8298
willy tarreau1c2ad212005-12-18 01:11:29 +01008299#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008300 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008301 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8302 epoll_loop(POLL_LOOP_ACTION_RUN);
8303 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008304 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008305 }
8306 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008307 Warning("epoll() is not available. Using poll()/select() instead.\n");
8308 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008309 }
8310 }
8311#endif
8312
8313#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008314 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008315 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8316 poll_loop(POLL_LOOP_ACTION_RUN);
8317 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008318 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008319 }
8320 else {
8321 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008322 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008323 }
8324 }
8325#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008326 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008327 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8328 select_loop(POLL_LOOP_ACTION_RUN);
8329 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008330 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008331 }
8332 }
8333
willy tarreau0f7af912005-12-17 12:21:26 +01008334
willy tarreau12350152005-12-18 01:03:27 +01008335 /* Free all Hash Keys and all Hash elements */
8336 appsession_cleanup();
8337 /* Do some cleanup */
8338 deinit();
8339
willy tarreau0f7af912005-12-17 12:21:26 +01008340 exit(0);
8341}
willy tarreau12350152005-12-18 01:03:27 +01008342
8343#if defined(DEBUG_HASH)
8344static void print_table(const CHTbl *htbl) {
8345
8346 ListElmt *element;
8347 int i;
8348 appsess *asession;
8349
8350 /*****************************************************************************
8351 * *
8352 * Display the chained hash table. *
8353 * *
8354 *****************************************************************************/
8355
8356 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8357
8358 for (i = 0; i < TBLSIZ; i++) {
8359 fprintf(stdout, "Bucket[%03d]\n", i);
8360
8361 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8362 //fprintf(stdout, "%c", *(char *)list_data(element));
8363 asession = (appsess *)list_data(element);
8364 fprintf(stdout, "ELEM :%s:", asession->sessid);
8365 fprintf(stdout, " Server :%s: \n", asession->serverid);
8366 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8367 }
8368
8369 fprintf(stdout, "\n");
8370 }
8371 return;
8372} /* end print_table */
8373#endif
8374
8375static int appsession_init(void)
8376{
8377 static int initialized = 0;
8378 int idlen;
8379 struct server *s;
8380 struct proxy *p = proxy;
8381
8382 if (!initialized) {
8383 if (!appsession_task_init()) {
8384 apools.sessid = NULL;
8385 apools.serverid = NULL;
8386 apools.ser_waste = 0;
8387 apools.ser_use = 0;
8388 apools.ser_msize = sizeof(void *);
8389 apools.ses_waste = 0;
8390 apools.ses_use = 0;
8391 apools.ses_msize = sizeof(void *);
8392 while (p) {
8393 s = p->srv;
8394 if (apools.ses_msize < p->appsession_len)
8395 apools.ses_msize = p->appsession_len;
8396 while (s) {
8397 idlen = strlen(s->id);
8398 if (apools.ser_msize < idlen)
8399 apools.ser_msize = idlen;
8400 s = s->next;
8401 }
8402 p = p->next;
8403 }
8404 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8405 apools.ses_msize ++;
8406 }
8407 else {
8408 fprintf(stderr, "appsession_task_init failed\n");
8409 return -1;
8410 }
8411 initialized ++;
8412 }
8413 return 0;
8414}
8415
8416static int appsession_task_init(void)
8417{
8418 static int initialized = 0;
8419 struct task *t;
8420 if (!initialized) {
8421 if ((t = pool_alloc(task)) == NULL)
8422 return -1;
8423 t->next = t->prev = t->rqnext = NULL;
8424 t->wq = LIST_HEAD(wait_queue);
8425 t->state = TASK_IDLE;
8426 t->context = NULL;
8427 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8428 task_queue(t);
8429 t->process = appsession_refresh;
8430 initialized ++;
8431 }
8432 return 0;
8433}
8434
8435static int appsession_refresh(struct task *t) {
8436 struct proxy *p = proxy;
8437 CHTbl *htbl;
8438 ListElmt *element, *last;
8439 int i;
8440 appsess *asession;
8441 void *data;
8442
8443 while (p) {
8444 if (p->appsession_name != NULL) {
8445 htbl = &p->htbl_proxy;
8446 /* if we ever give up the use of TBLSIZ, we need to change this */
8447 for (i = 0; i < TBLSIZ; i++) {
8448 last = NULL;
8449 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8450 asession = (appsess *)list_data(element);
8451 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8452 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8453 int len;
8454 /*
8455 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8456 */
8457 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8458 asession->sessid, asession->serverid?asession->serverid:"(null)");
8459 write(1, trash, len);
8460 }
8461 /* delete the expired element from within the hash table */
8462 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8463 && (htbl->table[i].destroy != NULL)) {
8464 htbl->table[i].destroy(data);
8465 }
8466 if (last == NULL) {/* patient lost his head, get a new one */
8467 element = list_head(&htbl->table[i]);
8468 if (element == NULL) break; /* no heads left, go to next patient */
8469 }
8470 else
8471 element = last;
8472 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8473 else
8474 last = element;
8475 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8476 }
8477 }
8478 p = p->next;
8479 }
8480 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8481 return TBLCHKINT;
8482} /* end appsession_refresh */
8483