blob: d03ec1f4e449f495df566eeb6a8ad22f5120b89d [file] [log] [blame]
willy tarreau0f7af912005-12-17 12:21:26 +01001/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01002 * HA-Proxy : High Availability-enabled HTTP/TCP proxy
willy tarreau726618c2006-01-29 22:42:06 +01003 * 2000-2006 - Willy Tarreau - willy AT meta-x DOT org.
willy tarreau0f7af912005-12-17 12:21:26 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
willy tarreau906b2682005-12-17 13:49:52 +010010 * Please refer to RFC2068 or RFC2616 for informations about HTTP protocol, and
willy tarreau982249e2005-12-18 00:57:06 +010011 * RFC2965 for informations about cookies usage. More generally, the IETF HTTP
12 * Working Group's web site should be consulted for protocol related changes :
13 *
14 * http://ftp.ics.uci.edu/pub/ietf/http/
willy tarreau906b2682005-12-17 13:49:52 +010015 *
16 * Pending bugs (may be not fixed because never reproduced) :
willy tarreaua1598082005-12-17 13:08:06 +010017 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
18 * the proxy to terminate (no core) if the client breaks the connection during
willy tarreauc29948c2005-12-17 13:10:27 +010019 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
willy tarreau8337c6b2005-12-17 13:41:01 +010020 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
21 * related to missing setsid() (fixed in 1.1.15)
willy tarreauef900ab2005-12-17 12:52:52 +010022 * - a proxy with an invalid config will prevent the startup even if disabled.
23 *
willy tarreau036e1ce2005-12-17 13:46:33 +010024 * ChangeLog has moved to the CHANGELOG file.
willy tarreau0f7af912005-12-17 12:21:26 +010025 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010026 * TODO:
27 * - handle properly intermediate incomplete server headers. Done ?
willy tarreau5cbea6f2005-12-17 12:48:26 +010028 * - handle hot-reconfiguration
willy tarreau906b2682005-12-17 13:49:52 +010029 * - fix client/server state transition when server is in connect or headers state
30 * and client suddenly disconnects. The server *should* switch to SHUT_WR, but
31 * still handle HTTP headers.
willy tarreau4302f492005-12-18 01:00:37 +010032 * - remove MAX_NEWHDR
willy tarreauc1f47532005-12-18 01:08:26 +010033 * - cut this huge file into several ones
willy tarreau0f7af912005-12-17 12:21:26 +010034 *
35 */
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <unistd.h>
40#include <string.h>
41#include <ctype.h>
42#include <sys/time.h>
43#include <sys/types.h>
44#include <sys/socket.h>
45#include <netinet/tcp.h>
46#include <netinet/in.h>
47#include <arpa/inet.h>
48#include <netdb.h>
49#include <fcntl.h>
50#include <errno.h>
51#include <signal.h>
52#include <stdarg.h>
53#include <sys/resource.h>
54#include <time.h>
willy tarreau0f7af912005-12-17 12:21:26 +010055#include <syslog.h>
willy tarreau77bc8542005-12-18 01:31:43 +010056
57#ifdef USE_PCRE
58#include <pcre.h>
59#include <pcreposix.h>
60#else
61#include <regex.h>
62#endif
63
willy tarreaua1598082005-12-17 13:08:06 +010064#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +010065#include <linux/netfilter_ipv4.h>
66#endif
willy tarreau0f7af912005-12-17 12:21:26 +010067
willy tarreau12350152005-12-18 01:03:27 +010068#if defined(__dietlibc__)
69#include <strings.h>
70#endif
71
willy tarreau1c2ad212005-12-18 01:11:29 +010072#if defined(ENABLE_POLL)
73#include <sys/poll.h>
74#endif
75
76#if defined(ENABLE_EPOLL)
77#if !defined(USE_MY_EPOLL)
willy tarreauad90a0c2005-12-18 01:09:15 +010078#include <sys/epoll.h>
willy tarreau1c2ad212005-12-18 01:11:29 +010079#else
80#include "include/epoll.h"
81#endif
82#endif
willy tarreauad90a0c2005-12-18 01:09:15 +010083
willy tarreau779dc892006-03-19 19:32:29 +010084#ifdef DEBUG_FULL
85#include <assert.h>
86#endif
87
willy tarreau598da412005-12-18 01:07:29 +010088#include "include/appsession.h"
willy tarreau12350152005-12-18 01:03:27 +010089
willy tarreaud8b1fa52006-03-19 21:01:07 +010090#define HAPROXY_VERSION "1.2.10"
91#define HAPROXY_DATE "2006/03/19"
willy tarreau0f7af912005-12-17 12:21:26 +010092
93/* this is for libc5 for example */
94#ifndef TCP_NODELAY
95#define TCP_NODELAY 1
96#endif
97
98#ifndef SHUT_RD
99#define SHUT_RD 0
100#endif
101
102#ifndef SHUT_WR
103#define SHUT_WR 1
104#endif
105
willy tarreau0174f312005-12-18 01:02:42 +0100106/*
107 * BUFSIZE defines the size of a read and write buffer. It is the maximum
108 * amount of bytes which can be stored by the proxy for each session. However,
109 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
110 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
111 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
112 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
113 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
114 */
115#ifndef BUFSIZE
116#define BUFSIZE 16384
117#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100118
119// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100120#ifndef MAXREWRITE
121#define MAXREWRITE (BUFSIZE / 2)
122#endif
123
willy tarreau9fe663a2005-12-17 13:02:59 +0100124#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100125#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100126
willy tarreau5cbea6f2005-12-17 12:48:26 +0100127// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100128#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100129
willy tarreaue39cd132005-12-17 13:00:18 +0100130// max # of added headers per request
131#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100132
133// max # of matches per regexp
134#define MAX_MATCH 10
135
willy tarreau0174f312005-12-18 01:02:42 +0100136// cookie delimitor in "prefix" mode. This character is inserted between the
137// persistence cookie and the original value. The '~' is allowed by RFC2965,
138// and should not be too common in server names.
139#ifndef COOKIE_DELIM
140#define COOKIE_DELIM '~'
141#endif
142
willy tarreau0f7af912005-12-17 12:21:26 +0100143#define CONN_RETRIES 3
144
willy tarreau5cbea6f2005-12-17 12:48:26 +0100145#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100146#define DEF_CHKINTR 2000
147#define DEF_FALLTIME 3
148#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100149#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100150
Willy TARREAU13032e72006-03-12 17:31:45 +0100151/* Default connections limit.
152 *
153 * A system limit can be enforced at build time in order to avoid using haproxy
154 * beyond reasonable system limits. For this, just define SYSTEM_MAXCONN to the
155 * absolute limit accepted by the system. If the configuration specifies a
156 * higher value, it will be capped to SYSTEM_MAXCONN and a warning will be
157 * emitted. The only way to override this limit will be to set it via the
158 * command-line '-n' argument.
159 */
160#ifndef SYSTEM_MAXCONN
willy tarreau9fe663a2005-12-17 13:02:59 +0100161#define DEFAULT_MAXCONN 2000
Willy TARREAU13032e72006-03-12 17:31:45 +0100162#else
163#define DEFAULT_MAXCONN SYSTEM_MAXCONN
164#endif
willy tarreau9fe663a2005-12-17 13:02:59 +0100165
willy tarreau0f7af912005-12-17 12:21:26 +0100166/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
167#define INTBITS 5
168
169/* show stats this every millisecond, 0 to disable */
170#ifndef STATTIME
171#define STATTIME 2000
172#endif
173
willy tarreau5cbea6f2005-12-17 12:48:26 +0100174/* this reduces the number of calls to select() by choosing appropriate
175 * sheduler precision in milliseconds. It should be near the minimum
176 * time that is needed by select() to collect all events. All timeouts
177 * are rounded up by adding this value prior to pass it to select().
178 */
179#define SCHEDULER_RESOLUTION 9
180
willy tarreaub952e1d2005-12-18 01:31:20 +0100181#define TIME_ETERNITY -1
182/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100183#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
184#define SETNOW(a) (*a=now)
185
willy tarreau9da061b2005-12-17 12:29:56 +0100186/****** string-specific macros and functions ******/
187/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
188#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
189
190/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
191#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
192
willy tarreau0174f312005-12-18 01:02:42 +0100193/* returns 1 only if only zero or one bit is set in X, which means that X is a
194 * power of 2, and 0 otherwise */
195#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100196/*
197 * copies at most <size-1> chars from <src> to <dst>. Last char is always
198 * set to 0, unless <size> is 0. The number of chars copied is returned
199 * (excluding the terminating zero).
200 * This code has been optimized for size and speed : on x86, it's 45 bytes
201 * long, uses only registers, and consumes only 4 cycles per char.
202 */
willy tarreau750a4722005-12-17 13:21:24 +0100203int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100204 char *orig = dst;
205 if (size) {
206 while (--size && (*dst = *src)) {
207 src++; dst++;
208 }
209 *dst = 0;
210 }
211 return dst - orig;
212}
willy tarreau9da061b2005-12-17 12:29:56 +0100213
willy tarreau4302f492005-12-18 01:00:37 +0100214/*
215 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
216 * dynamically allocated. In the first case, <__pool> is updated to point to
217 * the next element in the list.
218 */
219#define pool_alloc_from(__pool, __len) ({ \
220 void *__p; \
221 if ((__p = (__pool)) == NULL) \
222 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
223 else { \
224 __pool = *(void **)(__pool); \
225 } \
226 __p; \
227})
228
229/*
230 * Puts a memory area back to the corresponding pool.
231 * Items are chained directly through a pointer that
232 * is written in the beginning of the memory area, so
233 * there's no need for any carrier cell. This implies
234 * that each memory area is at least as big as one
235 * pointer.
236 */
237#define pool_free_to(__pool, __ptr) ({ \
238 *(void **)(__ptr) = (void *)(__pool); \
239 __pool = (void *)(__ptr); \
240})
241
242
willy tarreau0f7af912005-12-17 12:21:26 +0100243#define MEM_OPTIM
244#ifdef MEM_OPTIM
245/*
246 * Returns a pointer to type <type> taken from the
247 * pool <pool_type> or dynamically allocated. In the
248 * first case, <pool_type> is updated to point to the
249 * next element in the list.
250 */
251#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100252 void *__p; \
253 if ((__p = pool_##type) == NULL) \
254 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100255 else { \
256 pool_##type = *(void **)pool_##type; \
257 } \
willy tarreau4302f492005-12-18 01:00:37 +0100258 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100259})
260
261/*
262 * Puts a memory area back to the corresponding pool.
263 * Items are chained directly through a pointer that
264 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100265 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100266 * that each memory area is at least as big as one
267 * pointer.
268 */
269#define pool_free(type, ptr) ({ \
270 *(void **)ptr = (void *)pool_##type; \
271 pool_##type = (void *)ptr; \
272})
273
274#else
275#define pool_alloc(type) (calloc(1,sizeof_##type));
276#define pool_free(type, ptr) (free(ptr));
277#endif /* MEM_OPTIM */
278
willy tarreau5cbea6f2005-12-17 12:48:26 +0100279#define sizeof_task sizeof(struct task)
280#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100281#define sizeof_buffer sizeof(struct buffer)
282#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100283#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100284#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100285#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100286#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100287
willy tarreau5cbea6f2005-12-17 12:48:26 +0100288/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100289#define FD_STCLOSE 0
290#define FD_STLISTEN 1
291#define FD_STCONN 2
292#define FD_STREADY 3
293#define FD_STERROR 4
294
willy tarreau5cbea6f2005-12-17 12:48:26 +0100295/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100296#define TASK_IDLE 0
297#define TASK_RUNNING 1
298
willy tarreau5cbea6f2005-12-17 12:48:26 +0100299/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100300#define PR_STNEW 0
301#define PR_STIDLE 1
302#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100303#define PR_STSTOPPED 3
304#define PR_STPAUSED 4
willy tarreau0f7af912005-12-17 12:21:26 +0100305
willy tarreau5cbea6f2005-12-17 12:48:26 +0100306/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100307#define PR_MODE_TCP 0
308#define PR_MODE_HTTP 1
309#define PR_MODE_HEALTH 2
310
willy tarreau1c2ad212005-12-18 01:11:29 +0100311/* possible actions for the *poll() loops */
312#define POLL_LOOP_ACTION_INIT 0
313#define POLL_LOOP_ACTION_RUN 1
314#define POLL_LOOP_ACTION_CLEAN 2
315
willy tarreau64a3cc32005-12-18 01:13:11 +0100316/* poll mechanisms available */
317#define POLL_USE_SELECT (1<<0)
318#define POLL_USE_POLL (1<<1)
319#define POLL_USE_EPOLL (1<<2)
320
willy tarreau5cbea6f2005-12-17 12:48:26 +0100321/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100322#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
323#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
324#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
325#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
326#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
327#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
328#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
329#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100330#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau0174f312005-12-18 01:02:42 +0100331#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
332#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
333#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
334#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
335#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
336#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
337#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
338#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
339#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
340#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
341#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100342#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
343#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100344#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100345#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100346
willy tarreaue39cd132005-12-17 13:00:18 +0100347/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100348#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
349#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
350#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
351#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
352#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
353#define SN_POST 0x00000020 /* the request was an HTTP POST */
willy tarreaub1285d52005-12-18 01:20:14 +0100354#define SN_MONITOR 0x00000040 /* this session comes from a monitoring system */
willy tarreau036e1ce2005-12-17 13:46:33 +0100355
356#define SN_CK_NONE 0x00000000 /* this session had no cookie */
357#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
358#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
359#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
360#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
361#define SN_CK_SHIFT 6 /* bit shift */
362
willy tarreaub1285d52005-12-18 01:20:14 +0100363#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100364#define SN_ERR_CLITO 0x00000100 /* client time-out */
365#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
366#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
367#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
368#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100369#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
370#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100371#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
372#define SN_ERR_SHIFT 8 /* bit shift */
373
374#define SN_FINST_R 0x00001000 /* session ended during client request */
375#define SN_FINST_C 0x00002000 /* session ended during server connect */
376#define SN_FINST_H 0x00003000 /* session ended during server headers */
377#define SN_FINST_D 0x00004000 /* session ended during data phase */
378#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
379#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
380#define SN_FINST_SHIFT 12 /* bit shift */
381
382#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
383#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
384#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
385#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
386#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100387#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100388#define SN_SCK_SHIFT 16 /* bit shift */
389
willy tarreau97f58572005-12-18 00:53:44 +0100390#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
391#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
392#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100393
394/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100395#define CL_STHEADERS 0
396#define CL_STDATA 1
397#define CL_STSHUTR 2
398#define CL_STSHUTW 3
399#define CL_STCLOSE 4
400
willy tarreau5cbea6f2005-12-17 12:48:26 +0100401/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100402#define SV_STIDLE 0
403#define SV_STCONN 1
404#define SV_STHEADERS 2
405#define SV_STDATA 3
406#define SV_STSHUTR 4
407#define SV_STSHUTW 5
408#define SV_STCLOSE 6
409
410/* result of an I/O event */
411#define RES_SILENT 0 /* didn't happen */
412#define RES_DATA 1 /* data were sent or received */
413#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
414#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
415
willy tarreau9fe663a2005-12-17 13:02:59 +0100416/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100417#define MODE_DEBUG 1
418#define MODE_STATS 2
419#define MODE_LOG 4
420#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100421#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100422#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100423#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100424#define MODE_STARTING 128
willy tarreau5cbea6f2005-12-17 12:48:26 +0100425
426/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100427#define SRV_RUNNING 1 /* the server is UP */
428#define SRV_BACKUP 2 /* this server is a backup server */
429#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100430#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100431#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100432
willy tarreaue39cd132005-12-17 13:00:18 +0100433/* what to do when a header matches a regex */
434#define ACT_ALLOW 0 /* allow the request */
435#define ACT_REPLACE 1 /* replace the matching header */
436#define ACT_REMOVE 2 /* remove the matching header */
437#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100438#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100439
willy tarreau9fe663a2005-12-17 13:02:59 +0100440/* configuration sections */
441#define CFG_NONE 0
442#define CFG_GLOBAL 1
443#define CFG_LISTEN 2
444
willy tarreaua1598082005-12-17 13:08:06 +0100445/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100446#define LW_DATE 1 /* date */
447#define LW_CLIP 2 /* CLient IP */
448#define LW_SVIP 4 /* SerVer IP */
449#define LW_SVID 8 /* server ID */
450#define LW_REQ 16 /* http REQuest */
451#define LW_RESP 32 /* http RESPonse */
452#define LW_PXIP 64 /* proxy IP */
453#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100454#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100455#define LW_COOKIE 512 /* captured cookie */
456#define LW_REQHDR 1024 /* request header(s) */
457#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100458
willy tarreau0f7af912005-12-17 12:21:26 +0100459/*********************************************************************/
460
461#define LIST_HEAD(a) ((void *)(&(a)))
462
463/*********************************************************************/
464
willy tarreau4302f492005-12-18 01:00:37 +0100465struct cap_hdr {
466 struct cap_hdr *next;
467 char *name; /* header name, case insensitive */
468 int namelen; /* length of the header name, to speed-up lookups */
469 int len; /* capture length, not including terminal zero */
470 int index; /* index in the output array */
471 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
472};
473
willy tarreau0f7af912005-12-17 12:21:26 +0100474struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100475 struct hdr_exp *next;
476 regex_t *preg; /* expression to look for */
477 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
478 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100479};
480
481struct buffer {
482 unsigned int l; /* data length */
483 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100484 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100485 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100486 char data[BUFSIZE];
487};
488
489struct server {
490 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100491 int state; /* server state (SRV_*) */
492 int cklen; /* the len of the cookie, to speed up checks */
493 char *cookie; /* the id set in the cookie */
494 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100495 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100496 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100497 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100498 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100499 int rise, fall; /* time in iterations */
500 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100501 int result; /* 0 = connect OK, -1 = connect KO */
502 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100503 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100504};
505
willy tarreau5cbea6f2005-12-17 12:48:26 +0100506/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100507struct task {
508 struct task *next, *prev; /* chaining ... */
509 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100510 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100511 int state; /* task state : IDLE or RUNNING */
512 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100513 int (*process)(struct task *t); /* the function which processes the task */
514 void *context; /* the task's context */
515};
516
517/* WARNING: if new fields are added, they must be initialized in event_accept() */
518struct session {
519 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100520 /* application specific below */
521 struct timeval crexpire; /* expiration date for a client read */
522 struct timeval cwexpire; /* expiration date for a client write */
523 struct timeval srexpire; /* expiration date for a server read */
524 struct timeval swexpire; /* expiration date for a server write */
525 struct timeval cnexpire; /* expiration date for a connect */
526 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
527 struct proxy *proxy; /* the proxy this socket belongs to */
528 int cli_fd; /* the client side fd */
529 int srv_fd; /* the server side fd */
530 int cli_state; /* state of the client side */
531 int srv_state; /* state of the server side */
532 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100533 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100534 struct buffer *req; /* request buffer */
535 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100536 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100537 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100538 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100539 char **req_cap; /* array of captured request headers (may be NULL) */
540 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100541 struct {
542 int logwait; /* log fields waiting to be collected : LW_* */
543 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
544 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
545 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
546 long t_data; /* delay before the first data byte from the server ... */
547 unsigned long t_close; /* total session duration */
548 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100549 char *cli_cookie; /* cookie presented by the client, in capture mode */
550 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100551 int status; /* HTTP status from the server, negative if from proxy */
552 long long bytes; /* number of bytes transferred from the server */
553 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100554 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100555};
556
willy tarreaua41a8b42005-12-17 14:02:24 +0100557struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100558 int fd; /* the listen socket */
559 struct sockaddr_storage addr; /* the address we listen to */
560 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100561};
562
563
willy tarreau0f7af912005-12-17 12:21:26 +0100564struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100565 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100566 struct in_addr mon_net, mon_mask; /* don't forward connections from this net (network order) FIXME: should support IPv6 */
willy tarreau0f7af912005-12-17 12:21:26 +0100567 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100568 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100569 struct server *srv, *cursrv; /* known servers, current server */
570 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100571 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100572 int cookie_len; /* strlen(cookie_name), computed only once */
573 char *appsession_name; /* name of the cookie to look for */
574 int appsession_name_len; /* strlen(appsession_name), computed only once */
575 int appsession_len; /* length of the appsession cookie value to be used */
576 int appsession_timeout;
577 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100578 char *capture_name; /* beginning of the name of the cookie to capture */
579 int capture_namelen; /* length of the cookie name to match */
580 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100581 int clitimeout; /* client I/O timeout (in milliseconds) */
582 int srvtimeout; /* server I/O timeout (in milliseconds) */
583 int contimeout; /* connect timeout (in milliseconds) */
584 char *id; /* proxy id */
585 int nbconn; /* # of active sessions */
586 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100587 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100588 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100589 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100590 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100591 struct proxy *next;
592 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100593 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100594 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100595 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100596 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100597 int nb_reqadd, nb_rspadd;
598 struct hdr_exp *req_exp; /* regular expressions for request headers */
599 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100600 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
601 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
602 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
603 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100604 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100605 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100606 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
607 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100608 struct {
609 char *msg400; /* message for error 400 */
610 int len400; /* message length for error 400 */
611 char *msg403; /* message for error 403 */
612 int len403; /* message length for error 403 */
613 char *msg408; /* message for error 408 */
614 int len408; /* message length for error 408 */
615 char *msg500; /* message for error 500 */
616 int len500; /* message length for error 500 */
617 char *msg502; /* message for error 502 */
618 int len502; /* message length for error 502 */
619 char *msg503; /* message for error 503 */
620 int len503; /* message length for error 503 */
621 char *msg504; /* message for error 504 */
622 int len504; /* message length for error 504 */
623 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100624};
625
626/* info about one given fd */
627struct fdtab {
628 int (*read)(int fd); /* read function */
629 int (*write)(int fd); /* write function */
630 struct task *owner; /* the session (or proxy) associated with this fd */
631 int state; /* the state of this fd */
632};
633
634/*********************************************************************/
635
willy tarreaub952e1d2005-12-18 01:31:20 +0100636int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100637int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100638char *cfg_cfgfile = NULL; /* configuration file */
639char *progname = NULL; /* program name */
640int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100641
642/* global options */
643static struct {
644 int uid;
645 int gid;
646 int nbproc;
647 int maxconn;
648 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100649 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100650 int mode;
651 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100652 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100653 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100654 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100655 struct sockaddr_in logsrv1, logsrv2;
656} global = {
657 logfac1 : -1,
658 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100659 loglev1 : 7, /* max syslog level : debug */
660 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100661 /* others NULL OK */
662};
663
willy tarreau0f7af912005-12-17 12:21:26 +0100664/*********************************************************************/
665
willy tarreau1c2ad212005-12-18 01:11:29 +0100666fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100667 *StaticWriteEvent;
668
willy tarreau64a3cc32005-12-18 01:13:11 +0100669int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100670
willy tarreau0f7af912005-12-17 12:21:26 +0100671void **pool_session = NULL,
672 **pool_buffer = NULL,
673 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100674 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100675 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100676 **pool_capture = NULL,
677 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100678
679struct proxy *proxy = NULL; /* list of all existing proxies */
680struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100681struct task *rq = NULL; /* global run queue */
682struct task wait_queue = { /* global wait queue */
683 prev:LIST_HEAD(wait_queue),
684 next:LIST_HEAD(wait_queue)
685};
willy tarreau0f7af912005-12-17 12:21:26 +0100686
willy tarreau0f7af912005-12-17 12:21:26 +0100687static int totalconn = 0; /* total # of terminated sessions */
688static int actconn = 0; /* # of active sessions */
689static int maxfd = 0; /* # of the highest fd + 1 */
690static int listeners = 0; /* # of listeners */
691static int stopping = 0; /* non zero means stopping in progress */
692static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100693static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100694
willy tarreau08dedbe2005-12-18 01:13:48 +0100695#if defined(ENABLE_EPOLL)
696/* FIXME: this is dirty, but at the moment, there's no other solution to remove
697 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
698 * structure with pointers to functions such as init_fd() and close_fd(), plus
699 * a private structure with several pointers to places such as below.
700 */
701
702static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
703#endif
704
willy tarreau0f7af912005-12-17 12:21:26 +0100705static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100706/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100707static char trash[BUFSIZE];
708
willy tarreaudd07e972005-12-18 00:48:48 +0100709const int zero = 0;
710const int one = 1;
711
willy tarreau0f7af912005-12-17 12:21:26 +0100712/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100713 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100714 */
715
716#define MAX_SYSLOG_LEN 1024
717#define NB_LOG_FACILITIES 24
718const char *log_facilities[NB_LOG_FACILITIES] = {
719 "kern", "user", "mail", "daemon",
720 "auth", "syslog", "lpr", "news",
721 "uucp", "cron", "auth2", "ftp",
722 "ntp", "audit", "alert", "cron2",
723 "local0", "local1", "local2", "local3",
724 "local4", "local5", "local6", "local7"
725};
726
727
728#define NB_LOG_LEVELS 8
729const char *log_levels[NB_LOG_LEVELS] = {
730 "emerg", "alert", "crit", "err",
731 "warning", "notice", "info", "debug"
732};
733
734#define SYSLOG_PORT 514
735
736const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
737 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100738
willy tarreaub1285d52005-12-18 01:20:14 +0100739const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100740const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
741const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
742const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
743 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
744 unknown, Set-cookie Rewritten */
745
willy tarreau0f7af912005-12-17 12:21:26 +0100746#define MAX_HOSTNAME_LEN 32
747static char hostname[MAX_HOSTNAME_LEN] = "";
748
willy tarreau8337c6b2005-12-17 13:41:01 +0100749const char *HTTP_302 =
750 "HTTP/1.0 302 Found\r\n"
751 "Cache-Control: no-cache\r\n"
752 "Connection: close\r\n"
753 "Location: "; /* not terminated since it will be concatenated with the URL */
754
willy tarreauc1f47532005-12-18 01:08:26 +0100755/* same as 302 except that the browser MUST retry with the GET method */
756const char *HTTP_303 =
757 "HTTP/1.0 303 See Other\r\n"
758 "Cache-Control: no-cache\r\n"
759 "Connection: close\r\n"
760 "Location: "; /* not terminated since it will be concatenated with the URL */
761
willy tarreaua1598082005-12-17 13:08:06 +0100762const char *HTTP_400 =
763 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100764 "Cache-Control: no-cache\r\n"
765 "Connection: close\r\n"
766 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100767 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100768
willy tarreaua1598082005-12-17 13:08:06 +0100769const char *HTTP_403 =
770 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100771 "Cache-Control: no-cache\r\n"
772 "Connection: close\r\n"
773 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100774 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
775
willy tarreau8337c6b2005-12-17 13:41:01 +0100776const char *HTTP_408 =
777 "HTTP/1.0 408 Request Time-out\r\n"
778 "Cache-Control: no-cache\r\n"
779 "Connection: close\r\n"
780 "\r\n"
781 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
782
willy tarreau750a4722005-12-17 13:21:24 +0100783const char *HTTP_500 =
784 "HTTP/1.0 500 Server Error\r\n"
785 "Cache-Control: no-cache\r\n"
786 "Connection: close\r\n"
787 "\r\n"
788 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100789
790const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100791 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100792 "Cache-Control: no-cache\r\n"
793 "Connection: close\r\n"
794 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100795 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
796
797const char *HTTP_503 =
798 "HTTP/1.0 503 Service Unavailable\r\n"
799 "Cache-Control: no-cache\r\n"
800 "Connection: close\r\n"
801 "\r\n"
802 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
803
804const char *HTTP_504 =
805 "HTTP/1.0 504 Gateway Time-out\r\n"
806 "Cache-Control: no-cache\r\n"
807 "Connection: close\r\n"
808 "\r\n"
809 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100810
willy tarreau0f7af912005-12-17 12:21:26 +0100811/*********************************************************************/
812/* statistics ******************************************************/
813/*********************************************************************/
814
willy tarreau750a4722005-12-17 13:21:24 +0100815#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100816static int stats_tsk_lsrch, stats_tsk_rsrch,
817 stats_tsk_good, stats_tsk_right, stats_tsk_left,
818 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100819#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100820
821
822/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100823/* debugging *******************************************************/
824/*********************************************************************/
825#ifdef DEBUG_FULL
826static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
827static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
828#endif
829
830/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100831/* function prototypes *********************************************/
832/*********************************************************************/
833
834int event_accept(int fd);
835int event_cli_read(int fd);
836int event_cli_write(int fd);
837int event_srv_read(int fd);
838int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100839int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100840
willy tarreau12350152005-12-18 01:03:27 +0100841static int appsession_task_init(void);
842static int appsession_init(void);
843static int appsession_refresh(struct task *t);
844
willy tarreau0f7af912005-12-17 12:21:26 +0100845/*********************************************************************/
846/* general purpose functions ***************************************/
847/*********************************************************************/
848
849void display_version() {
850 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100851 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100852}
853
854/*
855 * This function prints the command line usage and exits
856 */
857void usage(char *name) {
858 display_version();
859 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100860 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100861#if STATTIME > 0
862 "sl"
863#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100864 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100865 " -v displays version\n"
866 " -d enters debug mode\n"
willy tarreau982249e2005-12-18 00:57:06 +0100867 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100868#if STATTIME > 0
869 " -s enables statistics output\n"
870 " -l enables long statistics format\n"
871#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100872 " -D goes daemon ; implies -q\n"
873 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100874 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100875 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100876 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100877 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100878#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100879 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100880#endif
881#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100882 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100883#endif
willy tarreauad90a0c2005-12-18 01:09:15 +0100884 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100885 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100886 exit(1);
887}
888
889
890/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100891 * Displays the message on stderr with the date and pid. Overrides the quiet
892 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100893 */
894void Alert(char *fmt, ...) {
895 va_list argp;
896 struct timeval tv;
897 struct tm *tm;
898
willy tarreaud0fb4652005-12-18 01:32:04 +0100899 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100900 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100901
willy tarreau5cbea6f2005-12-17 12:48:26 +0100902 gettimeofday(&tv, NULL);
903 tm=localtime(&tv.tv_sec);
904 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100905 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100906 vfprintf(stderr, fmt, argp);
907 fflush(stderr);
908 va_end(argp);
909 }
willy tarreau0f7af912005-12-17 12:21:26 +0100910}
911
912
913/*
914 * Displays the message on stderr with the date and pid.
915 */
916void Warning(char *fmt, ...) {
917 va_list argp;
918 struct timeval tv;
919 struct tm *tm;
920
willy tarreau982249e2005-12-18 00:57:06 +0100921 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100922 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100923
willy tarreau5cbea6f2005-12-17 12:48:26 +0100924 gettimeofday(&tv, NULL);
925 tm=localtime(&tv.tv_sec);
926 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100927 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100928 vfprintf(stderr, fmt, argp);
929 fflush(stderr);
930 va_end(argp);
931 }
932}
933
934/*
935 * Displays the message on <out> only if quiet mode is not set.
936 */
937void qfprintf(FILE *out, char *fmt, ...) {
938 va_list argp;
939
willy tarreau982249e2005-12-18 00:57:06 +0100940 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100941 va_start(argp, fmt);
942 vfprintf(out, fmt, argp);
943 fflush(out);
944 va_end(argp);
945 }
willy tarreau0f7af912005-12-17 12:21:26 +0100946}
947
948
949/*
950 * converts <str> to a struct sockaddr_in* which is locally allocated.
951 * The format is "addr:port", where "addr" can be empty or "*" to indicate
952 * INADDR_ANY.
953 */
954struct sockaddr_in *str2sa(char *str) {
955 static struct sockaddr_in sa;
956 char *c;
957 int port;
958
willy tarreaua1598082005-12-17 13:08:06 +0100959 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100960 str=strdup(str);
961
962 if ((c=strrchr(str,':')) != NULL) {
963 *c++=0;
964 port=atol(c);
965 }
966 else
967 port=0;
968
969 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
970 sa.sin_addr.s_addr = INADDR_ANY;
971 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100972 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100973 struct hostent *he;
974
975 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100976 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100977 }
978 else
979 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
980 }
981 sa.sin_port=htons(port);
982 sa.sin_family=AF_INET;
983
984 free(str);
985 return &sa;
986}
987
willy tarreaub1285d52005-12-18 01:20:14 +0100988/*
989 * converts <str> to a two struct in_addr* which are locally allocated.
990 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
991 * is optionnal and either in the dotted or CIDR notation.
992 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
993 */
994int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
995 char *c;
996 unsigned long len;
997
998 memset(mask, 0, sizeof(*mask));
999 memset(addr, 0, sizeof(*addr));
1000 str=strdup(str);
1001
1002 if ((c = strrchr(str, '/')) != NULL) {
1003 *c++ = 0;
1004 /* c points to the mask */
1005 if (strchr(c, '.') != NULL) { /* dotted notation */
1006 if (!inet_pton(AF_INET, c, mask))
1007 return 0;
1008 }
1009 else { /* mask length */
1010 char *err;
1011 len = strtol(c, &err, 10);
1012 if (!*c || (err && *err) || (unsigned)len > 32)
1013 return 0;
1014 if (len)
1015 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1016 else
1017 mask->s_addr = 0;
1018 }
1019 }
1020 else {
1021 mask->s_addr = 0xFFFFFFFF;
1022 }
1023 if (!inet_pton(AF_INET, str, addr)) {
1024 struct hostent *he;
1025
1026 if ((he = gethostbyname(str)) == NULL) {
1027 return 0;
1028 }
1029 else
1030 *addr = *(struct in_addr *) *(he->h_addr_list);
1031 }
1032 free(str);
1033 return 1;
1034}
1035
willy tarreau9fe663a2005-12-17 13:02:59 +01001036
1037/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001038 * converts <str> to a list of listeners which are dynamically allocated.
1039 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1040 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1041 * - <port> is a numerical port from 1 to 65535 ;
1042 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1043 * This can be repeated as many times as necessary, separated by a coma.
1044 * The <tail> argument is a pointer to a current list which should be appended
1045 * to the tail of the new list. The pointer to the new list is returned.
1046 */
1047struct listener *str2listener(char *str, struct listener *tail) {
1048 struct listener *l;
1049 char *c, *next, *range, *dupstr;
1050 int port, end;
1051
1052 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001053
willy tarreaua41a8b42005-12-17 14:02:24 +01001054 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001055 struct sockaddr_storage ss;
1056
willy tarreaua41a8b42005-12-17 14:02:24 +01001057 str = next;
1058 /* 1) look for the end of the first address */
1059 if ((next = strrchr(str, ',')) != NULL) {
1060 *next++ = 0;
1061 }
1062
willy tarreau8a86dbf2005-12-18 00:45:59 +01001063 /* 2) look for the addr/port delimiter, it's the last colon. */
1064 if ((range = strrchr(str, ':')) == NULL) {
1065 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001066 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001067 }
1068
1069 *range++ = 0;
1070
1071 if (strrchr(str, ':') != NULL) {
1072 /* IPv6 address contains ':' */
1073 memset(&ss, 0, sizeof(ss));
1074 ss.ss_family = AF_INET6;
1075
1076 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1077 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001078 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001079 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001080 }
1081 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001082 memset(&ss, 0, sizeof(ss));
1083 ss.ss_family = AF_INET;
1084
1085 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1086 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1087 }
1088 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1089 struct hostent *he;
1090
1091 if ((he = gethostbyname(str)) == NULL) {
1092 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001093 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001094 }
1095 else
1096 ((struct sockaddr_in *)&ss)->sin_addr =
1097 *(struct in_addr *) *(he->h_addr_list);
1098 }
1099 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001100
1101 /* 3) look for the port-end delimiter */
1102 if ((c = strchr(range, '-')) != NULL) {
1103 *c++ = 0;
1104 end = atol(c);
1105 }
1106 else {
1107 end = atol(range);
1108 }
1109
willy tarreaud0fb4652005-12-18 01:32:04 +01001110 port = atol(range);
1111
1112 if (port < 1 || port > 65535) {
1113 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1114 goto fail;
1115 }
1116
1117 if (end < 1 || end > 65535) {
1118 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1119 goto fail;
1120 }
1121
1122 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001123 l = (struct listener *)calloc(1, sizeof(struct listener));
1124 l->next = tail;
1125 tail = l;
1126
willy tarreau8a86dbf2005-12-18 00:45:59 +01001127 l->addr = ss;
1128 if (ss.ss_family == AF_INET6)
1129 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1130 else
1131 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1132
willy tarreaua41a8b42005-12-17 14:02:24 +01001133 } /* end for(port) */
1134 } /* end while(next) */
1135 free(dupstr);
1136 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001137 fail:
1138 free(dupstr);
1139 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001140}
1141
willy tarreau4302f492005-12-18 01:00:37 +01001142
1143#define FD_SETS_ARE_BITFIELDS
1144#ifdef FD_SETS_ARE_BITFIELDS
1145/*
1146 * This map is used with all the FD_* macros to check whether a particular bit
1147 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1148 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1149 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1150 * exclusively to the macros.
1151 */
1152fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1153fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1154
1155#else
1156#error "Check if your OS uses bitfields for fd_sets"
1157#endif
1158
1159/* will try to encode the string <string> replacing all characters tagged in
1160 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1161 * prefixed by <escape>, and will store the result between <start> (included
1162 *) and <stop> (excluded), and will always terminate the string with a '\0'
1163 * before <stop>. The position of the '\0' is returned if the conversion
1164 * completes. If bytes are missing between <start> and <stop>, then the
1165 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1166 * cannot even be stored so we return <start> without writing the 0.
1167 * The input string must also be zero-terminated.
1168 */
1169char hextab[16] = "0123456789ABCDEF";
1170char *encode_string(char *start, char *stop,
1171 const char escape, const fd_set *map,
1172 const char *string)
1173{
1174 if (start < stop) {
1175 stop--; /* reserve one byte for the final '\0' */
1176 while (start < stop && *string != 0) {
1177 if (!FD_ISSET((unsigned char)(*string), map))
1178 *start++ = *string;
1179 else {
1180 if (start + 3 >= stop)
1181 break;
1182 *start++ = escape;
1183 *start++ = hextab[(*string >> 4) & 15];
1184 *start++ = hextab[*string & 15];
1185 }
1186 string++;
1187 }
1188 *start = '\0';
1189 }
1190 return start;
1191}
willy tarreaua41a8b42005-12-17 14:02:24 +01001192
1193/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001194 * This function sends a syslog message to both log servers of a proxy,
1195 * or to global log servers if the proxy is NULL.
1196 * It also tries not to waste too much time computing the message header.
1197 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001198 */
1199void send_log(struct proxy *p, int level, char *message, ...) {
1200 static int logfd = -1; /* syslog UDP socket */
1201 static long tvsec = -1; /* to force the string to be initialized */
1202 struct timeval tv;
1203 va_list argp;
1204 static char logmsg[MAX_SYSLOG_LEN];
1205 static char *dataptr = NULL;
1206 int fac_level;
1207 int hdr_len, data_len;
1208 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001209 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001210 int nbloggers = 0;
1211 char *log_ptr;
1212
1213 if (logfd < 0) {
1214 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1215 return;
1216 }
1217
1218 if (level < 0 || progname == NULL || message == NULL)
1219 return;
1220
1221 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001222 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001223 /* this string is rebuild only once a second */
1224 struct tm *tm = localtime(&tv.tv_sec);
1225 tvsec = tv.tv_sec;
1226
willy tarreauc29948c2005-12-17 13:10:27 +01001227 hdr_len = snprintf(logmsg, sizeof(logmsg),
1228 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1229 monthname[tm->tm_mon],
1230 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1231 progname, pid);
1232 /* WARNING: depending upon implementations, snprintf may return
1233 * either -1 or the number of bytes that would be needed to store
1234 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001235 */
willy tarreauc29948c2005-12-17 13:10:27 +01001236 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1237 hdr_len = sizeof(logmsg);
1238
1239 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001240 }
1241
1242 va_start(argp, message);
1243 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001244 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1245 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001246 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001247 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001248
1249 if (p == NULL) {
1250 if (global.logfac1 >= 0) {
1251 sa[nbloggers] = &global.logsrv1;
1252 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001253 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001254 nbloggers++;
1255 }
1256 if (global.logfac2 >= 0) {
1257 sa[nbloggers] = &global.logsrv2;
1258 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001259 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001260 nbloggers++;
1261 }
1262 } else {
1263 if (p->logfac1 >= 0) {
1264 sa[nbloggers] = &p->logsrv1;
1265 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001266 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001267 nbloggers++;
1268 }
1269 if (p->logfac2 >= 0) {
1270 sa[nbloggers] = &p->logsrv2;
1271 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001272 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001273 nbloggers++;
1274 }
1275 }
1276
1277 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001278 /* we can filter the level of the messages that are sent to each logger */
1279 if (level > loglevel[nbloggers])
1280 continue;
1281
willy tarreauc29948c2005-12-17 13:10:27 +01001282 /* For each target, we may have a different facility.
1283 * We can also have a different log level for each message.
1284 * This induces variations in the message header length.
1285 * Since we don't want to recompute it each time, nor copy it every
1286 * time, we only change the facility in the pre-computed header,
1287 * and we change the pointer to the header accordingly.
1288 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001289 fac_level = (facilities[nbloggers] << 3) + level;
1290 log_ptr = logmsg + 3; /* last digit of the log level */
1291 do {
1292 *log_ptr = '0' + fac_level % 10;
1293 fac_level /= 10;
1294 log_ptr--;
1295 } while (fac_level && log_ptr > logmsg);
1296 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001297
willy tarreauc29948c2005-12-17 13:10:27 +01001298 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001299
1300#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001301 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001302 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1303#else
willy tarreauc29948c2005-12-17 13:10:27 +01001304 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001305 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1306#endif
1307 }
willy tarreau0f7af912005-12-17 12:21:26 +01001308}
1309
1310
1311/* sets <tv> to the current time */
1312static inline struct timeval *tv_now(struct timeval *tv) {
1313 if (tv)
1314 gettimeofday(tv, NULL);
1315 return tv;
1316}
1317
1318/*
1319 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1320 */
1321static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1322 if (!tv || !from)
1323 return NULL;
1324 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1325 tv->tv_sec = from->tv_sec + (ms/1000);
1326 while (tv->tv_usec >= 1000000) {
1327 tv->tv_usec -= 1000000;
1328 tv->tv_sec++;
1329 }
1330 return tv;
1331}
1332
1333/*
1334 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001335 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001336 */
1337static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001338 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001339 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001340 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001341 return 1;
1342 else if (tv1->tv_usec < tv2->tv_usec)
1343 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001344 else if (tv1->tv_usec > tv2->tv_usec)
1345 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001346 else
1347 return 0;
1348}
1349
1350/*
1351 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001352 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001353 */
1354unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1355 int cmp;
1356 unsigned long ret;
1357
1358
willy tarreauef900ab2005-12-17 12:52:52 +01001359 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001360 if (!cmp)
1361 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001362 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001363 struct timeval *tmp = tv1;
1364 tv1 = tv2;
1365 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001366 }
willy tarreauef900ab2005-12-17 12:52:52 +01001367 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001368 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001369 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001370 else
willy tarreauef900ab2005-12-17 12:52:52 +01001371 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001372 return (unsigned long) ret;
1373}
1374
1375/*
willy tarreau750a4722005-12-17 13:21:24 +01001376 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001377 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001378 */
1379static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1380 unsigned long ret;
1381
willy tarreau6e682ce2005-12-17 13:26:49 +01001382 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1383 if (tv2->tv_usec > tv1->tv_usec)
1384 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001385 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001386 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001387 return (unsigned long) ret;
1388}
1389
1390/*
willy tarreau0f7af912005-12-17 12:21:26 +01001391 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001392 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001393 */
1394static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001395 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001396 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001397 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001398 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001399 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001400 else
1401 return 0;
1402 }
willy tarreau0f7af912005-12-17 12:21:26 +01001403 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001404 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001405 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001406 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001407 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001408 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001409 else
1410 return 0;
1411}
1412
1413/*
1414 * returns the remaining time between tv1=now and event=tv2
1415 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001416 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001417 */
1418static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1419 unsigned long ret;
1420
willy tarreau0f7af912005-12-17 12:21:26 +01001421 if (tv_cmp_ms(tv1, tv2) >= 0)
1422 return 0; /* event elapsed */
1423
willy tarreauef900ab2005-12-17 12:52:52 +01001424 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001425 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001426 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001427 else
willy tarreauef900ab2005-12-17 12:52:52 +01001428 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001429 return (unsigned long) ret;
1430}
1431
1432
1433/*
1434 * zeroes a struct timeval
1435 */
1436
1437static inline struct timeval *tv_eternity(struct timeval *tv) {
1438 tv->tv_sec = tv->tv_usec = 0;
1439 return tv;
1440}
1441
1442/*
1443 * returns 1 if tv is null, else 0
1444 */
1445static inline int tv_iseternity(struct timeval *tv) {
1446 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1447 return 1;
1448 else
1449 return 0;
1450}
1451
1452/*
1453 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1454 * considering that 0 is the eternity.
1455 */
1456static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1457 if (tv_iseternity(tv1))
1458 if (tv_iseternity(tv2))
1459 return 0; /* same */
1460 else
1461 return 1; /* tv1 later than tv2 */
1462 else if (tv_iseternity(tv2))
1463 return -1; /* tv2 later than tv1 */
1464
1465 if (tv1->tv_sec > tv2->tv_sec)
1466 return 1;
1467 else if (tv1->tv_sec < tv2->tv_sec)
1468 return -1;
1469 else if (tv1->tv_usec > tv2->tv_usec)
1470 return 1;
1471 else if (tv1->tv_usec < tv2->tv_usec)
1472 return -1;
1473 else
1474 return 0;
1475}
1476
1477/*
1478 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1479 * considering that 0 is the eternity.
1480 */
1481static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1482 if (tv_iseternity(tv1))
1483 if (tv_iseternity(tv2))
1484 return 0; /* same */
1485 else
1486 return 1; /* tv1 later than tv2 */
1487 else if (tv_iseternity(tv2))
1488 return -1; /* tv2 later than tv1 */
1489
willy tarreauefae1842005-12-17 12:51:03 +01001490 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001491 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001492 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001493 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001494 return -1;
1495 else
1496 return 0;
1497 }
1498 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001499 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001500 return 1;
1501 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001502 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001503 return -1;
1504 else
1505 return 0;
1506}
1507
1508/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001509 * returns the remaining time between tv1=now and event=tv2
1510 * if tv2 is passed, 0 is returned.
1511 * Returns TIME_ETERNITY if tv2 is eternity.
1512 */
1513static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1514 unsigned long ret;
1515
1516 if (tv_iseternity(tv2))
1517 return TIME_ETERNITY;
1518
1519 if (tv_cmp_ms(tv1, tv2) >= 0)
1520 return 0; /* event elapsed */
1521
1522 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1523 if (tv2->tv_usec > tv1->tv_usec)
1524 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1525 else
1526 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1527 return (unsigned long) ret;
1528}
1529
1530/*
willy tarreau0f7af912005-12-17 12:21:26 +01001531 * returns the first event between tv1 and tv2 into tvmin.
1532 * a zero tv is ignored. tvmin is returned.
1533 */
1534static inline struct timeval *tv_min(struct timeval *tvmin,
1535 struct timeval *tv1, struct timeval *tv2) {
1536
1537 if (tv_cmp2(tv1, tv2) <= 0)
1538 *tvmin = *tv1;
1539 else
1540 *tvmin = *tv2;
1541
1542 return tvmin;
1543}
1544
1545
1546
1547/***********************************************************/
1548/* fd management ***************************************/
1549/***********************************************************/
1550
1551
1552
willy tarreau5cbea6f2005-12-17 12:48:26 +01001553/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1554 * The file descriptor is also closed.
1555 */
willy tarreau0f7af912005-12-17 12:21:26 +01001556static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001557 FD_CLR(fd, StaticReadEvent);
1558 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001559#if defined(ENABLE_EPOLL)
1560 if (PrevReadEvent) {
1561 FD_CLR(fd, PrevReadEvent);
1562 FD_CLR(fd, PrevWriteEvent);
1563 }
1564#endif
1565
willy tarreau5cbea6f2005-12-17 12:48:26 +01001566 close(fd);
1567 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001568
1569 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1570 maxfd--;
1571}
1572
1573/* recomputes the maxfd limit from the fd */
1574static inline void fd_insert(int fd) {
1575 if (fd+1 > maxfd)
1576 maxfd = fd+1;
1577}
1578
1579/*************************************************************/
1580/* task management ***************************************/
1581/*************************************************************/
1582
willy tarreau5cbea6f2005-12-17 12:48:26 +01001583/* puts the task <t> in run queue <q>, and returns <t> */
1584static inline struct task *task_wakeup(struct task **q, struct task *t) {
1585 if (t->state == TASK_RUNNING)
1586 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001587 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001588 t->rqnext = *q;
1589 t->state = TASK_RUNNING;
1590 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001591 }
1592}
1593
willy tarreau5cbea6f2005-12-17 12:48:26 +01001594/* removes the task <t> from the queue <q>
1595 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001596 * set the run queue to point to the next one, and return it
1597 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001598static inline struct task *task_sleep(struct task **q, struct task *t) {
1599 if (t->state == TASK_RUNNING) {
1600 *q = t->rqnext;
1601 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001602 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001603 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001604}
1605
1606/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001607 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001608 * from the run queue. A pointer to the task itself is returned.
1609 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001610static inline struct task *task_delete(struct task *t) {
1611 t->prev->next = t->next;
1612 t->next->prev = t->prev;
1613 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001614}
1615
1616/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001617 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001618 */
1619static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001620 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001621}
1622
willy tarreau5cbea6f2005-12-17 12:48:26 +01001623/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001624 * may be only moved or left where it was, depending on its timing requirements.
1625 * <task> is returned.
1626 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001627struct task *task_queue(struct task *task) {
1628 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001629 struct task *start_from;
1630
1631 /* first, test if the task was already in a list */
1632 if (task->prev == NULL) {
1633 // start_from = list;
1634 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001635#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001636 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001637#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001638 /* insert the unlinked <task> into the list, searching back from the last entry */
1639 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1640 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001641#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001642 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001643#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001644 }
1645
1646 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1647 // start_from = start_from->next;
1648 // stats_tsk_nsrch++;
1649 // }
1650 }
1651 else if (task->prev == list ||
1652 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1653 start_from = task->next;
1654 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001655#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001656 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001657#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001658 return task; /* it's already in the right place */
1659 }
1660
willy tarreau750a4722005-12-17 13:21:24 +01001661#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001662 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001663#endif
1664
1665 /* if the task is not at the right place, there's little chance that
1666 * it has only shifted a bit, and it will nearly always be queued
1667 * at the end of the list because of constant timeouts
1668 * (observed in real case).
1669 */
1670#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1671 start_from = list->prev; /* assume we'll queue to the end of the list */
1672 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1673 start_from = start_from->prev;
1674#if STATTIME > 0
1675 stats_tsk_lsrch++;
1676#endif
1677 }
1678#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001679 /* insert the unlinked <task> into the list, searching after position <start_from> */
1680 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1681 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001682#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001683 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001684#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001685 }
willy tarreau750a4722005-12-17 13:21:24 +01001686#endif /* WE_REALLY_... */
1687
willy tarreau0f7af912005-12-17 12:21:26 +01001688 /* we need to unlink it now */
1689 task_delete(task);
1690 }
1691 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001692#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001693 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001694#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001695#ifdef LEFT_TO_TOP /* not very good */
1696 start_from = list;
1697 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1698 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001699#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001700 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001701#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001702 }
1703#else
1704 start_from = task->prev->prev; /* valid because of the previous test above */
1705 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1706 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001707#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001708 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001709#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001710 }
1711#endif
1712 /* we need to unlink it now */
1713 task_delete(task);
1714 }
1715 task->prev = start_from;
1716 task->next = start_from->next;
1717 task->next->prev = task;
1718 start_from->next = task;
1719 return task;
1720}
1721
1722
1723/*********************************************************************/
1724/* more specific functions ***************************************/
1725/*********************************************************************/
1726
1727/* some prototypes */
1728static int maintain_proxies(void);
1729
willy tarreaub952e1d2005-12-18 01:31:20 +01001730/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001731 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1732 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001733static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001734#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001735 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1736#else
willy tarreaua1598082005-12-17 13:08:06 +01001737#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001738 return getsockname(fd, (struct sockaddr *)sa, salen);
1739#else
1740 return -1;
1741#endif
1742#endif
1743}
1744
1745/*
1746 * frees the context associated to a session. It must have been removed first.
1747 */
1748static inline void session_free(struct session *s) {
1749 if (s->req)
1750 pool_free(buffer, s->req);
1751 if (s->rep)
1752 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001753
1754 if (s->rsp_cap != NULL) {
1755 struct cap_hdr *h;
1756 for (h = s->proxy->rsp_cap; h; h = h->next) {
1757 if (s->rsp_cap[h->index] != NULL)
1758 pool_free_to(h->pool, s->rsp_cap[h->index]);
1759 }
1760 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1761 }
1762 if (s->req_cap != NULL) {
1763 struct cap_hdr *h;
1764 for (h = s->proxy->req_cap; h; h = h->next) {
1765 if (s->req_cap[h->index] != NULL)
1766 pool_free_to(h->pool, s->req_cap[h->index]);
1767 }
1768 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1769 }
1770
willy tarreaua1598082005-12-17 13:08:06 +01001771 if (s->logs.uri)
1772 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001773 if (s->logs.cli_cookie)
1774 pool_free(capture, s->logs.cli_cookie);
1775 if (s->logs.srv_cookie)
1776 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001777
willy tarreau5cbea6f2005-12-17 12:48:26 +01001778 pool_free(session, s);
1779}
1780
willy tarreau0f7af912005-12-17 12:21:26 +01001781
1782/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001783 * This function tries to find a running server for the proxy <px>. A first
1784 * pass looks for active servers, and if none is found, a second pass also
1785 * looks for backup servers.
1786 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1787 */
1788static inline struct server *find_server(struct proxy *px) {
1789 struct server *srv = px->cursrv;
willy tarreau72e583d2006-03-23 11:27:02 +01001790 struct server *end;
willy tarreau8337c6b2005-12-17 13:41:01 +01001791 int ignore_backup = 1;
1792
1793 do {
willy tarreau72e583d2006-03-23 11:27:02 +01001794 if (srv == NULL)
1795 srv = px->srv;
1796 end = srv;
willy tarreau8337c6b2005-12-17 13:41:01 +01001797 do {
willy tarreau8337c6b2005-12-17 13:41:01 +01001798 if (srv->state & SRV_RUNNING
1799 && !((srv->state & SRV_BACKUP) && ignore_backup))
1800 return srv;
1801 srv = srv->next;
willy tarreau72e583d2006-03-23 11:27:02 +01001802 if (srv == NULL)
1803 srv = px->srv;
1804 } while (srv != end);
Willy TARREAU3481c462006-03-01 22:37:57 +01001805
1806 /* By default, we look for the first backup server if all others are
1807 * DOWN. But in some cases, it may be desirable to load-balance across
1808 * all backup servers.
1809 */
1810 if (!(px->options & PR_O_USE_ALL_BK))
1811 srv = px->srv;
1812
willy tarreau8337c6b2005-12-17 13:41:01 +01001813 } while (ignore_backup--);
1814 return NULL;
1815}
1816
1817/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001818 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01001819 * is set, or to the dispatch server if (s->direct) is 0.
1820 * It can return one of :
1821 * - SN_ERR_NONE if everything's OK
1822 * - SN_ERR_SRVTO if there are no more servers
1823 * - SN_ERR_SRVCL if the connection was refused by the server
1824 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1825 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1826 * - SN_ERR_INTERNAL for any other purely internal errors
1827 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01001828 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001829int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001830 int fd;
1831
willy tarreau12350152005-12-18 01:03:27 +01001832#ifdef DEBUG_FULL
1833 fprintf(stderr,"connect_server : s=%p\n",s);
1834#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001835
willy tarreaue39cd132005-12-17 13:00:18 +01001836 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001837 s->srv_addr = s->srv->addr;
1838 }
1839 else if (s->proxy->options & PR_O_BALANCE) {
1840 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001841 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001842
willy tarreau8337c6b2005-12-17 13:41:01 +01001843 srv = find_server(s->proxy);
1844
1845 if (srv == NULL) /* no server left */
willy tarreaub1285d52005-12-18 01:20:14 +01001846 return SN_ERR_SRVTO;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001847
willy tarreau8337c6b2005-12-17 13:41:01 +01001848 s->srv_addr = srv->addr;
1849 s->srv = srv;
1850 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001851 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001852 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01001853 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001854 }
willy tarreaua1598082005-12-17 13:08:06 +01001855 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001856 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001857 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001858 }
1859 else if (s->proxy->options & PR_O_TRANSP) {
1860 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01001861 socklen_t salen = sizeof(s->srv_addr);
1862
willy tarreau5cbea6f2005-12-17 12:48:26 +01001863 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1864 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001865 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001866 }
1867 }
willy tarreau0f7af912005-12-17 12:21:26 +01001868
willy tarreaua41a8b42005-12-17 14:02:24 +01001869 /* if this server remaps proxied ports, we'll use
1870 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001871 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001872 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01001873 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01001874
willy tarreaub952e1d2005-12-18 01:31:20 +01001875 if (!(s->proxy->options & PR_O_TRANSP) ||
1876 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01001877 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1878 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1879 }
1880
willy tarreau0f7af912005-12-17 12:21:26 +01001881 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001882 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001883
1884 if (errno == ENFILE)
1885 send_log(s->proxy, LOG_EMERG,
1886 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
1887 s->proxy->id, maxfd);
1888 else if (errno == EMFILE)
1889 send_log(s->proxy, LOG_EMERG,
1890 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
1891 s->proxy->id, maxfd);
1892 else if (errno == ENOBUFS || errno == ENOMEM)
1893 send_log(s->proxy, LOG_EMERG,
1894 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
1895 s->proxy->id, maxfd);
1896 /* this is a resource error */
1897 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01001898 }
1899
willy tarreau9fe663a2005-12-17 13:02:59 +01001900 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01001901 /* do not log anything there, it's a normal condition when this option
1902 * is used to serialize connections to a server !
1903 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001904 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1905 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001906 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001907 }
1908
willy tarreau0f7af912005-12-17 12:21:26 +01001909 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1910 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001911 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001912 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001913 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001914 }
1915
willy tarreaub952e1d2005-12-18 01:31:20 +01001916 if (s->proxy->options & PR_O_TCP_SRV_KA)
1917 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
1918
willy tarreau0174f312005-12-18 01:02:42 +01001919 /* allow specific binding :
1920 * - server-specific at first
1921 * - proxy-specific next
1922 */
1923 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
1924 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1925 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
1926 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
1927 s->proxy->id, s->srv->id);
1928 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001929 send_log(s->proxy, LOG_EMERG,
1930 "Cannot bind to source address before connect() for server %s/%s.\n",
1931 s->proxy->id, s->srv->id);
1932 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001933 }
1934 }
1935 else if (s->proxy->options & PR_O_BIND_SRC) {
1936 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1937 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1938 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1939 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001940 send_log(s->proxy, LOG_EMERG,
1941 "Cannot bind to source address before connect() for server %s/%s.\n",
1942 s->proxy->id, s->srv->id);
1943 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001944 }
willy tarreaua1598082005-12-17 13:08:06 +01001945 }
1946
willy tarreaub1285d52005-12-18 01:20:14 +01001947 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
1948 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
1949
1950 if (errno == EAGAIN || errno == EADDRINUSE) {
1951 char *msg;
1952 if (errno == EAGAIN) /* no free ports left, try again later */
1953 msg = "no free ports";
1954 else
1955 msg = "local address already in use";
1956
1957 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01001958 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001959 send_log(s->proxy, LOG_EMERG,
1960 "Connect() failed for server %s/%s: %s.\n",
1961 s->proxy->id, s->srv->id, msg);
1962 return SN_ERR_RESOURCE;
1963 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001964 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01001965 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001966 return SN_ERR_SRVTO;
1967 } else {
1968 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01001969 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01001970 close(fd);
1971 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01001972 }
1973 }
1974
willy tarreau5cbea6f2005-12-17 12:48:26 +01001975 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001976 fdtab[fd].read = &event_srv_read;
1977 fdtab[fd].write = &event_srv_write;
1978 fdtab[fd].state = FD_STCONN; /* connection in progress */
1979
1980 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01001981#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
1982 if (PrevReadEvent) {
1983 assert(!(FD_ISSET(fd, PrevReadEvent)));
1984 assert(!(FD_ISSET(fd, PrevWriteEvent)));
1985 }
1986#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001987
1988 fd_insert(fd);
1989
1990 if (s->proxy->contimeout)
1991 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1992 else
1993 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01001994 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01001995}
1996
1997/*
1998 * this function is called on a read event from a client socket.
1999 * It returns 0.
2000 */
2001int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002002 struct task *t = fdtab[fd].owner;
2003 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002004 struct buffer *b = s->req;
2005 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002006
willy tarreau12350152005-12-18 01:03:27 +01002007#ifdef DEBUG_FULL
2008 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2009#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002010
willy tarreau0f7af912005-12-17 12:21:26 +01002011 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002012#ifdef FILL_BUFFERS
2013 while (1)
2014#else
2015 do
2016#endif
2017 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002018 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2019 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002020 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002021 }
2022 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002023 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002024 }
2025 else {
2026 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002027 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2028 * since it means that the rewrite protection has been removed. This
2029 * implies that the if statement can be removed.
2030 */
2031 if (max > b->rlim - b->data)
2032 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002033 }
2034
2035 if (max == 0) { /* not anymore room to store data */
2036 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002037 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002038 }
2039
willy tarreau3242e862005-12-17 12:27:53 +01002040#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002041 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002042 int skerr;
2043 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002044
willy tarreau5cbea6f2005-12-17 12:48:26 +01002045 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2046 if (skerr)
2047 ret = -1;
2048 else
2049 ret = recv(fd, b->r, max, 0);
2050 }
willy tarreau3242e862005-12-17 12:27:53 +01002051#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002052 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002053#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002054 if (ret > 0) {
2055 b->r += ret;
2056 b->l += ret;
2057 s->res_cr = RES_DATA;
2058
2059 if (b->r == b->data + BUFSIZE) {
2060 b->r = b->data; /* wrap around the buffer */
2061 }
willy tarreaua1598082005-12-17 13:08:06 +01002062
2063 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002064 /* we hope to read more data or to get a close on next round */
2065 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002066 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002067 else if (ret == 0) {
2068 s->res_cr = RES_NULL;
2069 break;
2070 }
2071 else if (errno == EAGAIN) {/* ignore EAGAIN */
2072 break;
2073 }
2074 else {
2075 s->res_cr = RES_ERROR;
2076 fdtab[fd].state = FD_STERROR;
2077 break;
2078 }
2079 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002080#ifndef FILL_BUFFERS
2081 while (0);
2082#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002083 }
2084 else {
2085 s->res_cr = RES_ERROR;
2086 fdtab[fd].state = FD_STERROR;
2087 }
2088
willy tarreau5cbea6f2005-12-17 12:48:26 +01002089 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002090 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002091 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2092 else
2093 tv_eternity(&s->crexpire);
2094
2095 task_wakeup(&rq, t);
2096 }
willy tarreau0f7af912005-12-17 12:21:26 +01002097
willy tarreau0f7af912005-12-17 12:21:26 +01002098 return 0;
2099}
2100
2101
2102/*
2103 * this function is called on a read event from a server socket.
2104 * It returns 0.
2105 */
2106int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002107 struct task *t = fdtab[fd].owner;
2108 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002109 struct buffer *b = s->rep;
2110 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002111
willy tarreau12350152005-12-18 01:03:27 +01002112#ifdef DEBUG_FULL
2113 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2114#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002115
willy tarreau0f7af912005-12-17 12:21:26 +01002116 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002117#ifdef FILL_BUFFERS
2118 while (1)
2119#else
2120 do
2121#endif
2122 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002123 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2124 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002125 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002126 }
2127 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002128 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002129 }
2130 else {
2131 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002132 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2133 * since it means that the rewrite protection has been removed. This
2134 * implies that the if statement can be removed.
2135 */
2136 if (max > b->rlim - b->data)
2137 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002138 }
2139
2140 if (max == 0) { /* not anymore room to store data */
2141 FD_CLR(fd, StaticReadEvent);
2142 break;
2143 }
2144
willy tarreau3242e862005-12-17 12:27:53 +01002145#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002146 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002147 int skerr;
2148 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002149
willy tarreau5cbea6f2005-12-17 12:48:26 +01002150 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2151 if (skerr)
2152 ret = -1;
2153 else
2154 ret = recv(fd, b->r, max, 0);
2155 }
willy tarreau3242e862005-12-17 12:27:53 +01002156#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002157 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002158#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002159 if (ret > 0) {
2160 b->r += ret;
2161 b->l += ret;
2162 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002163
willy tarreau5cbea6f2005-12-17 12:48:26 +01002164 if (b->r == b->data + BUFSIZE) {
2165 b->r = b->data; /* wrap around the buffer */
2166 }
willy tarreaua1598082005-12-17 13:08:06 +01002167
2168 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002169 /* we hope to read more data or to get a close on next round */
2170 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002171 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002172 else if (ret == 0) {
2173 s->res_sr = RES_NULL;
2174 break;
2175 }
2176 else if (errno == EAGAIN) {/* ignore EAGAIN */
2177 break;
2178 }
2179 else {
2180 s->res_sr = RES_ERROR;
2181 fdtab[fd].state = FD_STERROR;
2182 break;
2183 }
2184 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002185#ifndef FILL_BUFFERS
2186 while (0);
2187#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002188 }
2189 else {
2190 s->res_sr = RES_ERROR;
2191 fdtab[fd].state = FD_STERROR;
2192 }
2193
willy tarreau5cbea6f2005-12-17 12:48:26 +01002194 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002195 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002196 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2197 else
2198 tv_eternity(&s->srexpire);
2199
2200 task_wakeup(&rq, t);
2201 }
willy tarreau0f7af912005-12-17 12:21:26 +01002202
willy tarreau0f7af912005-12-17 12:21:26 +01002203 return 0;
2204}
2205
2206/*
2207 * this function is called on a write event from a client socket.
2208 * It returns 0.
2209 */
2210int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002211 struct task *t = fdtab[fd].owner;
2212 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002213 struct buffer *b = s->rep;
2214 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002215
willy tarreau12350152005-12-18 01:03:27 +01002216#ifdef DEBUG_FULL
2217 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2218#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002219
2220 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002221 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002222 // max = BUFSIZE; BUG !!!!
2223 max = 0;
2224 }
2225 else if (b->r > b->w) {
2226 max = b->r - b->w;
2227 }
2228 else
2229 max = b->data + BUFSIZE - b->w;
2230
willy tarreau0f7af912005-12-17 12:21:26 +01002231 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002232 if (max == 0) {
2233 s->res_cw = RES_NULL;
2234 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002235 tv_eternity(&s->cwexpire);
2236 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002237 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002238 }
2239
willy tarreau3242e862005-12-17 12:27:53 +01002240#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002241 {
2242 int skerr;
2243 socklen_t lskerr = sizeof(skerr);
2244
2245 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2246 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002247 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002248 else
willy tarreau3242e862005-12-17 12:27:53 +01002249 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002250 }
willy tarreau3242e862005-12-17 12:27:53 +01002251#else
willy tarreau0f7af912005-12-17 12:21:26 +01002252 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002253#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002254
2255 if (ret > 0) {
2256 b->l -= ret;
2257 b->w += ret;
2258
2259 s->res_cw = RES_DATA;
2260
2261 if (b->w == b->data + BUFSIZE) {
2262 b->w = b->data; /* wrap around the buffer */
2263 }
2264 }
2265 else if (ret == 0) {
2266 /* nothing written, just make as if we were never called */
2267// s->res_cw = RES_NULL;
2268 return 0;
2269 }
2270 else if (errno == EAGAIN) /* ignore EAGAIN */
2271 return 0;
2272 else {
2273 s->res_cw = RES_ERROR;
2274 fdtab[fd].state = FD_STERROR;
2275 }
2276 }
2277 else {
2278 s->res_cw = RES_ERROR;
2279 fdtab[fd].state = FD_STERROR;
2280 }
2281
willy tarreaub1ff9db2005-12-17 13:51:03 +01002282 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002283 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002284 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2285 s->crexpire = s->cwexpire;
2286 }
willy tarreau0f7af912005-12-17 12:21:26 +01002287 else
2288 tv_eternity(&s->cwexpire);
2289
willy tarreau5cbea6f2005-12-17 12:48:26 +01002290 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002291 return 0;
2292}
2293
2294
2295/*
2296 * this function is called on a write event from a server socket.
2297 * It returns 0.
2298 */
2299int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002300 struct task *t = fdtab[fd].owner;
2301 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002302 struct buffer *b = s->req;
2303 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002304
willy tarreau12350152005-12-18 01:03:27 +01002305#ifdef DEBUG_FULL
2306 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2307#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002308
2309 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002310 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002311 // max = BUFSIZE; BUG !!!!
2312 max = 0;
2313 }
2314 else if (b->r > b->w) {
2315 max = b->r - b->w;
2316 }
2317 else
2318 max = b->data + BUFSIZE - b->w;
2319
willy tarreau0f7af912005-12-17 12:21:26 +01002320 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002321 if (max == 0) {
2322 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002323 if (s->srv_state == SV_STCONN) {
2324 int skerr;
2325 socklen_t lskerr = sizeof(skerr);
2326 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2327 if (skerr) {
2328 s->res_sw = RES_ERROR;
2329 fdtab[fd].state = FD_STERROR;
2330 task_wakeup(&rq, t);
2331 tv_eternity(&s->swexpire);
2332 FD_CLR(fd, StaticWriteEvent);
2333 return 0;
2334 }
2335 }
2336
willy tarreau0f7af912005-12-17 12:21:26 +01002337 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002338 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002339 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002340 tv_eternity(&s->swexpire);
2341 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002342 return 0;
2343 }
2344
willy tarreau3242e862005-12-17 12:27:53 +01002345#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002346 {
2347 int skerr;
2348 socklen_t lskerr = sizeof(skerr);
2349 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2350 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002351 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002352 else
willy tarreau3242e862005-12-17 12:27:53 +01002353 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002354 }
willy tarreau3242e862005-12-17 12:27:53 +01002355#else
willy tarreau0f7af912005-12-17 12:21:26 +01002356 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002357#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002358 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002359 if (ret > 0) {
2360 b->l -= ret;
2361 b->w += ret;
2362
2363 s->res_sw = RES_DATA;
2364
2365 if (b->w == b->data + BUFSIZE) {
2366 b->w = b->data; /* wrap around the buffer */
2367 }
2368 }
2369 else if (ret == 0) {
2370 /* nothing written, just make as if we were never called */
2371 // s->res_sw = RES_NULL;
2372 return 0;
2373 }
2374 else if (errno == EAGAIN) /* ignore EAGAIN */
2375 return 0;
2376 else {
2377 s->res_sw = RES_ERROR;
2378 fdtab[fd].state = FD_STERROR;
2379 }
2380 }
2381 else {
2382 s->res_sw = RES_ERROR;
2383 fdtab[fd].state = FD_STERROR;
2384 }
2385
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002386 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2387 * otherwise it could loop indefinitely !
2388 */
2389 if (s->srv_state != SV_STCONN) {
2390 if (s->proxy->srvtimeout) {
2391 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
2392 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2393 s->srexpire = s->swexpire;
2394 }
2395 else
2396 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002397 }
willy tarreau0f7af912005-12-17 12:21:26 +01002398
willy tarreau5cbea6f2005-12-17 12:48:26 +01002399 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002400 return 0;
2401}
2402
2403
2404/*
willy tarreaue39cd132005-12-17 13:00:18 +01002405 * returns a message to the client ; the connection is shut down for read,
2406 * and the request is cleared so that no server connection can be initiated.
2407 * The client must be in a valid state for this (HEADER, DATA ...).
2408 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002409 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002410 */
2411void client_retnclose(struct session *s, int len, const char *msg) {
2412 FD_CLR(s->cli_fd, StaticReadEvent);
2413 FD_SET(s->cli_fd, StaticWriteEvent);
2414 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002415 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002416 shutdown(s->cli_fd, SHUT_RD);
2417 s->cli_state = CL_STSHUTR;
2418 strcpy(s->rep->data, msg);
2419 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002420 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002421 s->rep->r += len;
2422 s->req->l = 0;
2423}
2424
2425
2426/*
2427 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002428 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002429 */
2430void client_return(struct session *s, int len, const char *msg) {
2431 strcpy(s->rep->data, msg);
2432 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002433 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002434 s->rep->r += len;
2435 s->req->l = 0;
2436}
2437
willy tarreau9fe663a2005-12-17 13:02:59 +01002438/*
2439 * send a log for the session when we have enough info about it
2440 */
2441void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002442 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002443 struct proxy *p = s->proxy;
2444 int log;
2445 char *uri;
2446 char *pxid;
2447 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002448 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002449
2450 /* This is a first attempt at a better logging system.
2451 * For now, we rely on send_log() to provide the date, although it obviously
2452 * is the date of the log and not of the request, and most fields are not
2453 * computed.
2454 */
2455
willy tarreaua1598082005-12-17 13:08:06 +01002456 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002457
willy tarreau8a86dbf2005-12-18 00:45:59 +01002458 if (s->cli_addr.ss_family == AF_INET)
2459 inet_ntop(AF_INET,
2460 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2461 pn, sizeof(pn));
2462 else
2463 inet_ntop(AF_INET6,
2464 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2465 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002466
willy tarreauc1cae632005-12-17 14:12:23 +01002467 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002468 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002469 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002470
willy tarreauc1cae632005-12-17 14:12:23 +01002471 tm = localtime(&s->logs.tv_accept.tv_sec);
2472 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002473 char tmpline[MAX_SYSLOG_LEN], *h;
2474 int hdr;
2475
2476 h = tmpline;
2477 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2478 *(h++) = ' ';
2479 *(h++) = '{';
2480 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2481 if (hdr)
2482 *(h++) = '|';
2483 if (s->req_cap[hdr] != NULL)
2484 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2485 }
2486 *(h++) = '}';
2487 }
2488
2489 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2490 *(h++) = ' ';
2491 *(h++) = '{';
2492 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2493 if (hdr)
2494 *(h++) = '|';
2495 if (s->rsp_cap[hdr] != NULL)
2496 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2497 }
2498 *(h++) = '}';
2499 }
2500
2501 if (h < tmpline + sizeof(tmpline) - 4) {
2502 *(h++) = ' ';
2503 *(h++) = '"';
2504 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2505 *(h++) = '"';
2506 }
2507 *h = '\0';
2508
willy tarreau0fe39652005-12-18 01:25:24 +01002509 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 +01002510 pn,
2511 (s->cli_addr.ss_family == AF_INET) ?
2512 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2513 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002514 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2515 tm->tm_hour, tm->tm_min, tm->tm_sec,
2516 pxid, srv,
2517 s->logs.t_request,
2518 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2519 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002520 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2521 s->logs.status,
2522 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002523 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2524 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002525 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2526 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2527 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2528 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau0fe39652005-12-18 01:25:24 +01002529 p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002530 }
2531 else {
willy tarreau0fe39652005-12-18 01:25:24 +01002532 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 +01002533 pn,
2534 (s->cli_addr.ss_family == AF_INET) ?
2535 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2536 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002537 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2538 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002539 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002540 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002541 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2542 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002543 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002544 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2545 p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002546 }
2547
2548 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002549}
2550
willy tarreaue39cd132005-12-17 13:00:18 +01002551
2552/*
willy tarreau0f7af912005-12-17 12:21:26 +01002553 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002554 * to an accept. It tries to accept as many connections as possible.
2555 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002556 */
2557int event_accept(int fd) {
2558 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002559 struct session *s;
2560 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002561 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01002562 int max_accept;
2563
2564 if (global.nbproc > 1)
2565 max_accept = 8; /* let other processes catch some connections too */
2566 else
2567 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01002568
willy tarreauc2becdc2006-03-19 19:36:48 +01002569 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002570 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002571 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002572
willy tarreaub1285d52005-12-18 01:20:14 +01002573 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2574 switch (errno) {
2575 case EAGAIN:
2576 case EINTR:
2577 case ECONNABORTED:
2578 return 0; /* nothing more to accept */
2579 case ENFILE:
2580 send_log(p, LOG_EMERG,
2581 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2582 p->id, maxfd);
2583 return 0;
2584 case EMFILE:
2585 send_log(p, LOG_EMERG,
2586 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2587 p->id, maxfd);
2588 return 0;
2589 case ENOBUFS:
2590 case ENOMEM:
2591 send_log(p, LOG_EMERG,
2592 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2593 p->id, maxfd);
2594 return 0;
2595 default:
2596 return 0;
2597 }
2598 }
willy tarreau0f7af912005-12-17 12:21:26 +01002599
willy tarreau5cbea6f2005-12-17 12:48:26 +01002600 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2601 Alert("out of memory in event_accept().\n");
2602 FD_CLR(fd, StaticReadEvent);
2603 p->state = PR_STIDLE;
2604 close(cfd);
2605 return 0;
2606 }
willy tarreau0f7af912005-12-17 12:21:26 +01002607
willy tarreaub1285d52005-12-18 01:20:14 +01002608 /* if this session comes from a known monitoring system, we want to ignore
2609 * it as soon as possible, which means closing it immediately for TCP.
2610 */
2611 s->flags = 0;
2612 if (addr.ss_family == AF_INET &&
2613 p->mon_mask.s_addr &&
2614 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2615 if (p->mode == PR_MODE_TCP) {
2616 close(cfd);
2617 pool_free(session, s);
2618 continue;
2619 }
2620 s->flags |= SN_MONITOR;
2621 }
2622
willy tarreau5cbea6f2005-12-17 12:48:26 +01002623 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2624 Alert("out of memory in event_accept().\n");
2625 FD_CLR(fd, StaticReadEvent);
2626 p->state = PR_STIDLE;
2627 close(cfd);
2628 pool_free(session, s);
2629 return 0;
2630 }
willy tarreau0f7af912005-12-17 12:21:26 +01002631
willy tarreau5cbea6f2005-12-17 12:48:26 +01002632 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002633 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002634 Alert("accept(): not enough free sockets. Raise -n argument. 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 tarreau5cbea6f2005-12-17 12:48:26 +01002641 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2642 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2643 (char *) &one, sizeof(one)) == -1)) {
2644 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2645 close(cfd);
2646 pool_free(task, t);
2647 pool_free(session, s);
2648 return 0;
2649 }
willy tarreau0f7af912005-12-17 12:21:26 +01002650
willy tarreaub952e1d2005-12-18 01:31:20 +01002651 if (p->options & PR_O_TCP_CLI_KA)
2652 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2653
willy tarreau9fe663a2005-12-17 13:02:59 +01002654 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2655 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2656 t->state = TASK_IDLE;
2657 t->process = process_session;
2658 t->context = s;
2659
2660 s->task = t;
2661 s->proxy = p;
2662 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2663 s->srv_state = SV_STIDLE;
2664 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002665
willy tarreau9fe663a2005-12-17 13:02:59 +01002666 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2667 s->cli_fd = cfd;
2668 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002669 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002670 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002671
willy tarreaub1285d52005-12-18 01:20:14 +01002672 if (s->flags & SN_MONITOR)
2673 s->logs.logwait = 0;
2674 else
2675 s->logs.logwait = p->to_log;
2676
willy tarreaua1598082005-12-17 13:08:06 +01002677 s->logs.tv_accept = now;
2678 s->logs.t_request = -1;
2679 s->logs.t_connect = -1;
2680 s->logs.t_data = -1;
2681 s->logs.t_close = 0;
2682 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002683 s->logs.cli_cookie = NULL;
2684 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002685 s->logs.status = -1;
2686 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002687
willy tarreau2f6ba652005-12-17 13:57:42 +01002688 s->uniq_id = totalconn;
2689
willy tarreau4302f492005-12-18 01:00:37 +01002690 if (p->nb_req_cap > 0) {
2691 if ((s->req_cap =
2692 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2693 == NULL) { /* no memory */
2694 close(cfd); /* nothing can be done for this fd without memory */
2695 pool_free(task, t);
2696 pool_free(session, s);
2697 return 0;
2698 }
2699 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2700 }
2701 else
2702 s->req_cap = NULL;
2703
2704 if (p->nb_rsp_cap > 0) {
2705 if ((s->rsp_cap =
2706 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2707 == NULL) { /* no memory */
2708 if (s->req_cap != NULL)
2709 pool_free_to(p->req_cap_pool, s->req_cap);
2710 close(cfd); /* nothing can be done for this fd without memory */
2711 pool_free(task, t);
2712 pool_free(session, s);
2713 return 0;
2714 }
2715 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2716 }
2717 else
2718 s->rsp_cap = NULL;
2719
willy tarreau5cbea6f2005-12-17 12:48:26 +01002720 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2721 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002722 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002723 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002724
willy tarreau8a86dbf2005-12-18 00:45:59 +01002725 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002726 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002727 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002728 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002729
willy tarreau9fe663a2005-12-17 13:02:59 +01002730 if (p->to_log) {
2731 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002732 if (s->logs.logwait & LW_CLIP)
2733 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002734 sess_log(s);
2735 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002736 else if (s->cli_addr.ss_family == AF_INET) {
2737 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2738 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2739 sn, sizeof(sn)) &&
2740 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2741 pn, sizeof(pn))) {
2742 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2743 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2744 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2745 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2746 }
2747 }
2748 else {
2749 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2750 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2751 sn, sizeof(sn)) &&
2752 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2753 pn, sizeof(pn))) {
2754 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2755 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2756 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2757 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2758 }
2759 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002760 }
willy tarreau0f7af912005-12-17 12:21:26 +01002761
willy tarreau982249e2005-12-18 00:57:06 +01002762 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002763 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002764 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002765 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002766 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002767 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002768 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002769 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002770
willy tarreau8a86dbf2005-12-18 00:45:59 +01002771 if (s->cli_addr.ss_family == AF_INET) {
2772 char pn[INET_ADDRSTRLEN];
2773 inet_ntop(AF_INET,
2774 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_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_in *)&s->cli_addr)->sin_port));
2780 }
2781 else {
2782 char pn[INET6_ADDRSTRLEN];
2783 inet_ntop(AF_INET6,
2784 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2785 pn, sizeof(pn));
2786
2787 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2788 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2789 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2790 }
2791
willy tarreauef900ab2005-12-17 12:52:52 +01002792 write(1, trash, len);
2793 }
willy tarreau0f7af912005-12-17 12:21:26 +01002794
willy tarreau5cbea6f2005-12-17 12:48:26 +01002795 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002796 if (s->rsp_cap != NULL)
2797 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2798 if (s->req_cap != NULL)
2799 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002800 close(cfd); /* nothing can be done for this fd without memory */
2801 pool_free(task, t);
2802 pool_free(session, s);
2803 return 0;
2804 }
willy tarreau4302f492005-12-18 01:00:37 +01002805
willy tarreau5cbea6f2005-12-17 12:48:26 +01002806 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002807 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002808 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2809 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002810 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002811 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002812
willy tarreau5cbea6f2005-12-17 12:48:26 +01002813 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2814 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002815 if (s->rsp_cap != NULL)
2816 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2817 if (s->req_cap != NULL)
2818 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002819 close(cfd); /* nothing can be done for this fd without memory */
2820 pool_free(task, t);
2821 pool_free(session, s);
2822 return 0;
2823 }
2824 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002825 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002826 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 +01002827
willy tarreau5cbea6f2005-12-17 12:48:26 +01002828 fdtab[cfd].read = &event_cli_read;
2829 fdtab[cfd].write = &event_cli_write;
2830 fdtab[cfd].owner = t;
2831 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002832
willy tarreaub1285d52005-12-18 01:20:14 +01002833 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2834 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2835 /* Either we got a request from a monitoring system on an HTTP instance,
2836 * or we're in health check mode with the 'httpchk' option enabled. In
2837 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2838 */
2839 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2840 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2841 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002842 }
2843 else {
2844 FD_SET(cfd, StaticReadEvent);
2845 }
2846
willy tarreaub952e1d2005-12-18 01:31:20 +01002847#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2848 if (PrevReadEvent) {
2849 assert(!(FD_ISSET(cfd, PrevReadEvent)));
2850 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
2851 }
2852#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002853 fd_insert(cfd);
2854
2855 tv_eternity(&s->cnexpire);
2856 tv_eternity(&s->srexpire);
2857 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01002858 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002859 tv_eternity(&s->cwexpire);
2860
willy tarreaub1285d52005-12-18 01:20:14 +01002861 if (s->proxy->clitimeout) {
2862 if (FD_ISSET(cfd, StaticReadEvent))
2863 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2864 if (FD_ISSET(cfd, StaticWriteEvent))
2865 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
2866 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002867
willy tarreaub1285d52005-12-18 01:20:14 +01002868 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002869
2870 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002871
2872 if (p->mode != PR_MODE_HEALTH)
2873 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002874
2875 p->nbconn++;
2876 actconn++;
2877 totalconn++;
2878
willy tarreaub952e1d2005-12-18 01:31:20 +01002879 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002880 } /* end of while (p->nbconn < p->maxconn) */
2881 return 0;
2882}
willy tarreau0f7af912005-12-17 12:21:26 +01002883
willy tarreau0f7af912005-12-17 12:21:26 +01002884
willy tarreau5cbea6f2005-12-17 12:48:26 +01002885/*
2886 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002887 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2888 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002889 * or -1 if an error occured.
2890 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002891int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002892 struct task *t = fdtab[fd].owner;
2893 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002894 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01002895 socklen_t lskerr = sizeof(skerr);
2896
willy tarreau05be12b2006-03-19 19:35:00 +01002897 skerr = 1;
2898 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
2899 || (skerr != 0)) {
2900 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002901 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01002902 fdtab[fd].state = FD_STERROR;
2903 FD_CLR(fd, StaticWriteEvent);
2904 }
willy tarreaua4a583a2005-12-18 01:39:19 +01002905 else if (s->result != -1) {
2906 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002907 if (s->proxy->options & PR_O_HTTP_CHK) {
2908 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002909 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002910 * so we'll send the request, and won't wake the checker up now.
2911 */
2912#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002913 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002914#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002915 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002916#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002917 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002918 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2919 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2920 return 0;
2921 }
willy tarreau05be12b2006-03-19 19:35:00 +01002922 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002923 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01002924 FD_CLR(fd, StaticWriteEvent);
2925 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002926 }
2927 else {
2928 /* good TCP connection is enough */
2929 s->result = 1;
2930 }
2931 }
2932
2933 task_wakeup(&rq, t);
2934 return 0;
2935}
2936
willy tarreau0f7af912005-12-17 12:21:26 +01002937
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002938/*
2939 * This function is used only for server health-checks. It handles
2940 * the server's reply to an HTTP request. It returns 1 if the server replies
2941 * 2xx or 3xx (valid responses), or -1 in other cases.
2942 */
2943int event_srv_chk_r(int fd) {
2944 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01002945 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002946 struct task *t = fdtab[fd].owner;
2947 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01002948 int skerr;
2949 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002950
willy tarreaua4a583a2005-12-18 01:39:19 +01002951 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002952
willy tarreau05be12b2006-03-19 19:35:00 +01002953 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2954 if (!skerr) {
2955#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002956 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002957#else
willy tarreau05be12b2006-03-19 19:35:00 +01002958 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2959 * but the connection was closed on the remote end. Fortunately, recv still
2960 * works correctly and we don't need to do the getsockopt() on linux.
2961 */
2962 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002963#endif
willy tarreau05be12b2006-03-19 19:35:00 +01002964
2965 if ((len >= sizeof("HTTP/1.0 000")) &&
2966 !memcmp(reply, "HTTP/1.", 7) &&
2967 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2968 result = 1;
2969 }
2970
2971 if (result == -1)
2972 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01002973
2974 if (s->result != -1)
2975 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002976
2977 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002978 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002979 return 0;
2980}
2981
2982
2983/*
2984 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2985 * and moves <end> just after the end of <str>.
2986 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2987 * the shift value (positive or negative) is returned.
2988 * If there's no space left, the move is not done.
2989 *
2990 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002991int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002992 int delta;
2993 int len;
2994
2995 len = strlen(str);
2996 delta = len - (end - pos);
2997
2998 if (delta + b->r >= b->data + BUFSIZE)
2999 return 0; /* no space left */
3000
3001 /* first, protect the end of the buffer */
3002 memmove(end + delta, end, b->data + b->l - end);
3003
3004 /* now, copy str over pos */
3005 memcpy(pos, str,len);
3006
willy tarreau5cbea6f2005-12-17 12:48:26 +01003007 /* we only move data after the displaced zone */
3008 if (b->r > pos) b->r += delta;
3009 if (b->w > pos) b->w += delta;
3010 if (b->h > pos) b->h += delta;
3011 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003012 b->l += delta;
3013
3014 return delta;
3015}
3016
willy tarreau8337c6b2005-12-17 13:41:01 +01003017/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003018 * len is 0.
3019 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003020int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003021 int delta;
3022
3023 delta = len - (end - pos);
3024
3025 if (delta + b->r >= b->data + BUFSIZE)
3026 return 0; /* no space left */
3027
Willy TARREAUe78ae262006-01-08 01:24:12 +01003028 if (b->data + b->l < end)
3029 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3030 return 0;
3031
willy tarreau0f7af912005-12-17 12:21:26 +01003032 /* first, protect the end of the buffer */
3033 memmove(end + delta, end, b->data + b->l - end);
3034
3035 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003036 if (len)
3037 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003038
willy tarreau5cbea6f2005-12-17 12:48:26 +01003039 /* we only move data after the displaced zone */
3040 if (b->r > pos) b->r += delta;
3041 if (b->w > pos) b->w += delta;
3042 if (b->h > pos) b->h += delta;
3043 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003044 b->l += delta;
3045
3046 return delta;
3047}
3048
3049
3050int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3051 char *old_dst = dst;
3052
3053 while (*str) {
3054 if (*str == '\\') {
3055 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003056 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003057 int len, num;
3058
3059 num = *str - '0';
3060 str++;
3061
willy tarreau8a86dbf2005-12-18 00:45:59 +01003062 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003063 len = matches[num].rm_eo - matches[num].rm_so;
3064 memcpy(dst, src + matches[num].rm_so, len);
3065 dst += len;
3066 }
3067
3068 }
3069 else if (*str == 'x') {
3070 unsigned char hex1, hex2;
3071 str++;
3072
willy tarreauc1f47532005-12-18 01:08:26 +01003073 hex1 = toupper(*str++) - '0';
3074 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003075
3076 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3077 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3078 *dst++ = (hex1<<4) + hex2;
3079 }
3080 else
3081 *dst++ = *str++;
3082 }
3083 else
3084 *dst++ = *str++;
3085 }
3086 *dst = 0;
3087 return dst - old_dst;
3088}
3089
willy tarreauc1f47532005-12-18 01:08:26 +01003090static int ishex(char s)
3091{
3092 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3093}
3094
3095/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3096char *check_replace_string(char *str)
3097{
3098 char *err = NULL;
3099 while (*str) {
3100 if (*str == '\\') {
3101 err = str; /* in case of a backslash, we return the pointer to it */
3102 str++;
3103 if (!*str)
3104 return err;
3105 else if (isdigit((int)*str))
3106 err = NULL;
3107 else if (*str == 'x') {
3108 str++;
3109 if (!ishex(*str))
3110 return err;
3111 str++;
3112 if (!ishex(*str))
3113 return err;
3114 err = NULL;
3115 }
3116 else {
3117 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3118 err = NULL;
3119 }
3120 }
3121 str++;
3122 }
3123 return err;
3124}
3125
3126
willy tarreau9fe663a2005-12-17 13:02:59 +01003127
willy tarreau0f7af912005-12-17 12:21:26 +01003128/*
3129 * manages the client FSM and its socket. BTW, it also tries to handle the
3130 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3131 * 0 else.
3132 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003133int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003134 int s = t->srv_state;
3135 int c = t->cli_state;
3136 struct buffer *req = t->req;
3137 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003138 int method_checked = 0;
3139 appsess *asession_temp = NULL;
3140 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003141
willy tarreau750a4722005-12-17 13:21:24 +01003142#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003143 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3144 cli_stnames[c], srv_stnames[s],
3145 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3146 t->crexpire.tv_sec, t->crexpire.tv_usec,
3147 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003148#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003149 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3150 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3151 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3152 //);
3153 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003154 /* now parse the partial (or complete) headers */
3155 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3156 char *ptr;
3157 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003158 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003159
willy tarreau5cbea6f2005-12-17 12:48:26 +01003160 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003161
willy tarreau0f7af912005-12-17 12:21:26 +01003162 /* look for the end of the current header */
3163 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3164 ptr++;
3165
willy tarreau5cbea6f2005-12-17 12:48:26 +01003166 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003167 int line, len;
3168 /* we can only get here after an end of headers */
3169 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003170
willy tarreaue39cd132005-12-17 13:00:18 +01003171 if (t->flags & SN_CLDENY) {
3172 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003173 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003174 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003175 if (!(t->flags & SN_ERR_MASK))
3176 t->flags |= SN_ERR_PRXCOND;
3177 if (!(t->flags & SN_FINST_MASK))
3178 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003179 return 1;
3180 }
3181
willy tarreau5cbea6f2005-12-17 12:48:26 +01003182 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003183 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3184 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003185 }
willy tarreau0f7af912005-12-17 12:21:26 +01003186
willy tarreau9fe663a2005-12-17 13:02:59 +01003187 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003188 if (t->cli_addr.ss_family == AF_INET) {
3189 unsigned char *pn;
3190 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3191 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3192 pn[0], pn[1], pn[2], pn[3]);
3193 buffer_replace2(req, req->h, req->h, trash, len);
3194 }
3195 else if (t->cli_addr.ss_family == AF_INET6) {
3196 char pn[INET6_ADDRSTRLEN];
3197 inet_ntop(AF_INET6,
3198 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3199 pn, sizeof(pn));
3200 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3201 buffer_replace2(req, req->h, req->h, trash, len);
3202 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003203 }
3204
willy tarreau25c4ea52005-12-18 00:49:49 +01003205 /* add a "connection: close" line if needed */
3206 if (t->proxy->options & PR_O_HTTP_CLOSE)
3207 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3208
willy tarreau982249e2005-12-18 00:57:06 +01003209 if (!memcmp(req->data, "POST ", 5)) {
3210 /* this is a POST request, which is not cacheable by default */
3211 t->flags |= SN_POST;
3212 }
willy tarreaucd878942005-12-17 13:27:43 +01003213
willy tarreau5cbea6f2005-12-17 12:48:26 +01003214 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003215 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003216
willy tarreau750a4722005-12-17 13:21:24 +01003217 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003218 /* FIXME: we'll set the client in a wait state while we try to
3219 * connect to the server. Is this really needed ? wouldn't it be
3220 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003221 //FD_CLR(t->cli_fd, StaticReadEvent);
3222 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003223
3224 /* FIXME: if we break here (as up to 1.1.23), having the client
3225 * shutdown its connection can lead to an abort further.
3226 * it's better to either return 1 or even jump directly to the
3227 * data state which will save one schedule.
3228 */
3229 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003230
3231 if (!t->proxy->clitimeout ||
3232 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3233 /* If the client has no timeout, or if the server is not ready yet,
3234 * and we know for sure that it can expire, then it's cleaner to
3235 * disable the timeout on the client side so that too low values
3236 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003237 *
3238 * FIXME-20050705: the server needs a way to re-enable this time-out
3239 * when it switches its state, otherwise a client can stay connected
3240 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003241 */
3242 tv_eternity(&t->crexpire);
3243
willy tarreau197e8ec2005-12-17 14:10:59 +01003244 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003245 }
willy tarreau0f7af912005-12-17 12:21:26 +01003246
Willy TARREAU13032e72006-03-12 17:31:45 +01003247 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3248 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003249 /* this is a partial header, let's wait for more to come */
3250 req->lr = ptr;
3251 break;
3252 }
willy tarreau0f7af912005-12-17 12:21:26 +01003253
willy tarreau5cbea6f2005-12-17 12:48:26 +01003254 /* now we know that *ptr is either \r or \n,
3255 * and that there are at least 1 char after it.
3256 */
3257 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3258 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3259 else
3260 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003261
willy tarreau5cbea6f2005-12-17 12:48:26 +01003262 /*
3263 * now we know that we have a full header ; we can do whatever
3264 * we want with these pointers :
3265 * req->h = beginning of header
3266 * ptr = end of header (first \r or \n)
3267 * req->lr = beginning of next line (next rep->h)
3268 * req->r = end of data (not used at this stage)
3269 */
willy tarreau0f7af912005-12-17 12:21:26 +01003270
willy tarreau12350152005-12-18 01:03:27 +01003271 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3272 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3273 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3274
3275 /* skip ; */
3276 request_line++;
3277
3278 /* look if we have a jsessionid */
3279
3280 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3281
3282 /* skip jsessionid= */
3283 request_line += t->proxy->appsession_name_len + 1;
3284
3285 /* First try if we allready have an appsession */
3286 asession_temp = &local_asession;
3287
3288 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3289 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3290 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3291 return 0;
3292 }
3293
3294 /* Copy the sessionid */
3295 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3296 asession_temp->sessid[t->proxy->appsession_len] = 0;
3297 asession_temp->serverid = NULL;
3298
3299 /* only do insert, if lookup fails */
3300 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3301 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3302 Alert("Not enough memory process_cli():asession:calloc().\n");
3303 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3304 return 0;
3305 }
3306 asession_temp->sessid = local_asession.sessid;
3307 asession_temp->serverid = local_asession.serverid;
3308 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003309 } /* end if (chtbl_lookup()) */
3310 else {
willy tarreau12350152005-12-18 01:03:27 +01003311 /*free wasted memory;*/
3312 pool_free_to(apools.sessid, local_asession.sessid);
3313 }
3314
3315 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3316 asession_temp->request_count++;
3317
3318#if defined(DEBUG_HASH)
3319 print_table(&(t->proxy->htbl_proxy));
3320#endif
3321
3322 if (asession_temp->serverid == NULL) {
3323 Alert("Found Application Session without matching server.\n");
3324 } else {
3325 struct server *srv = t->proxy->srv;
3326 while (srv) {
3327 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3328 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3329 /* we found the server and it's usable */
3330 t->flags &= ~SN_CK_MASK;
3331 t->flags |= SN_CK_VALID | SN_DIRECT;
3332 t->srv = srv;
3333 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003334 } else {
willy tarreau12350152005-12-18 01:03:27 +01003335 t->flags &= ~SN_CK_MASK;
3336 t->flags |= SN_CK_DOWN;
3337 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003338 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003339 srv = srv->next;
3340 }/* end while(srv) */
3341 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003342 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003343 else {
3344 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3345 }
willy tarreau598da412005-12-18 01:07:29 +01003346 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003347 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003348 else{
3349 //printf("No Methode-Header with Session-String\n");
3350 }
3351
willy tarreau8337c6b2005-12-17 13:41:01 +01003352 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003353 /* we have a complete HTTP request that we must log */
3354 int urilen;
3355
willy tarreaua1598082005-12-17 13:08:06 +01003356 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003357 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003358 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003359 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003360 if (!(t->flags & SN_ERR_MASK))
3361 t->flags |= SN_ERR_PRXCOND;
3362 if (!(t->flags & SN_FINST_MASK))
3363 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003364 return 1;
3365 }
3366
3367 urilen = ptr - req->h;
3368 if (urilen >= REQURI_LEN)
3369 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003370 memcpy(t->logs.uri, req->h, urilen);
3371 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003372
willy tarreaua1598082005-12-17 13:08:06 +01003373 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003374 sess_log(t);
3375 }
willy tarreau4302f492005-12-18 01:00:37 +01003376 else if (t->logs.logwait & LW_REQHDR) {
3377 struct cap_hdr *h;
3378 int len;
3379 for (h = t->proxy->req_cap; h; h = h->next) {
3380 if ((h->namelen + 2 <= ptr - req->h) &&
3381 (req->h[h->namelen] == ':') &&
3382 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3383
3384 if (t->req_cap[h->index] == NULL)
3385 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3386
3387 len = ptr - (req->h + h->namelen + 2);
3388 if (len > h->len)
3389 len = h->len;
3390
3391 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3392 t->req_cap[h->index][len]=0;
3393 }
3394 }
3395
3396 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003397
willy tarreau5cbea6f2005-12-17 12:48:26 +01003398 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003399
willy tarreau982249e2005-12-18 00:57:06 +01003400 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003401 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003402 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 +01003403 max = ptr - req->h;
3404 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003405 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003406 trash[len++] = '\n';
3407 write(1, trash, len);
3408 }
willy tarreau0f7af912005-12-17 12:21:26 +01003409
willy tarreau25c4ea52005-12-18 00:49:49 +01003410
3411 /* remove "connection: " if needed */
3412 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3413 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3414 delete_header = 1;
3415 }
3416
willy tarreau5cbea6f2005-12-17 12:48:26 +01003417 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003418 if (!delete_header && t->proxy->req_exp != NULL
3419 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003420 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003421 char term;
3422
3423 term = *ptr;
3424 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003425 exp = t->proxy->req_exp;
3426 do {
3427 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3428 switch (exp->action) {
3429 case ACT_ALLOW:
3430 if (!(t->flags & SN_CLDENY))
3431 t->flags |= SN_CLALLOW;
3432 break;
3433 case ACT_REPLACE:
3434 if (!(t->flags & SN_CLDENY)) {
3435 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3436 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3437 }
3438 break;
3439 case ACT_REMOVE:
3440 if (!(t->flags & SN_CLDENY))
3441 delete_header = 1;
3442 break;
3443 case ACT_DENY:
3444 if (!(t->flags & SN_CLALLOW))
3445 t->flags |= SN_CLDENY;
3446 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003447 case ACT_PASS: /* we simply don't deny this one */
3448 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003449 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003450 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003451 }
willy tarreaue39cd132005-12-17 13:00:18 +01003452 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003453 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003454 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003455
willy tarreau240afa62005-12-17 13:14:35 +01003456 /* Now look for cookies. Conforming to RFC2109, we have to support
3457 * attributes whose name begin with a '$', and associate them with
3458 * the right cookie, if we want to delete this cookie.
3459 * So there are 3 cases for each cookie read :
3460 * 1) it's a special attribute, beginning with a '$' : ignore it.
3461 * 2) it's a server id cookie that we *MAY* want to delete : save
3462 * some pointers on it (last semi-colon, beginning of cookie...)
3463 * 3) it's an application cookie : we *MAY* have to delete a previous
3464 * "special" cookie.
3465 * At the end of loop, if a "special" cookie remains, we may have to
3466 * remove it. If no application cookie persists in the header, we
3467 * *MUST* delete it
3468 */
willy tarreau12350152005-12-18 01:03:27 +01003469 if (!delete_header &&
3470 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003471 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003472 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003473 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003474 char *del_colon, *del_cookie, *colon;
3475 int app_cookies;
3476
willy tarreau5cbea6f2005-12-17 12:48:26 +01003477 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003478 colon = p1;
3479 /* del_cookie == NULL => nothing to be deleted */
3480 del_colon = del_cookie = NULL;
3481 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003482
3483 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003484 /* skip spaces and colons, but keep an eye on these ones */
3485 while (p1 < ptr) {
3486 if (*p1 == ';' || *p1 == ',')
3487 colon = p1;
3488 else if (!isspace((int)*p1))
3489 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003490 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003491 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003492
3493 if (p1 == ptr)
3494 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003495
3496 /* p1 is at the beginning of the cookie name */
3497 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003498 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003499 p2++;
3500
3501 if (p2 == ptr)
3502 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003503
3504 p3 = p2 + 1; /* skips the '=' sign */
3505 if (p3 == ptr)
3506 break;
3507
willy tarreau240afa62005-12-17 13:14:35 +01003508 p4 = p3;
3509 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003510 p4++;
3511
3512 /* here, we have the cookie name between p1 and p2,
3513 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003514 * we can process it :
3515 *
3516 * Cookie: NAME=VALUE;
3517 * | || || |
3518 * | || || +--> p4
3519 * | || |+-------> p3
3520 * | || +--------> p2
3521 * | |+------------> p1
3522 * | +-------------> colon
3523 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003524 */
3525
willy tarreau240afa62005-12-17 13:14:35 +01003526 if (*p1 == '$') {
3527 /* skip this one */
3528 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003529 else {
3530 /* first, let's see if we want to capture it */
3531 if (t->proxy->capture_name != NULL &&
3532 t->logs.cli_cookie == NULL &&
3533 (p4 - p1 >= t->proxy->capture_namelen) &&
3534 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3535 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003536
willy tarreau8337c6b2005-12-17 13:41:01 +01003537 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3538 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003539 } else {
3540 if (log_len > t->proxy->capture_len)
3541 log_len = t->proxy->capture_len;
3542 memcpy(t->logs.cli_cookie, p1, log_len);
3543 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003544 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003545 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003546
3547 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3548 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3549 /* Cool... it's the right one */
3550 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003551 char *delim;
3552
3553 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3554 * have the server ID betweek p3 and delim, and the original cookie between
3555 * delim+1 and p4. Otherwise, delim==p4 :
3556 *
3557 * Cookie: NAME=SRV~VALUE;
3558 * | || || | |
3559 * | || || | +--> p4
3560 * | || || +--------> delim
3561 * | || |+-----------> p3
3562 * | || +------------> p2
3563 * | |+----------------> p1
3564 * | +-----------------> colon
3565 * +------------------------> req->h
3566 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003567
willy tarreau0174f312005-12-18 01:02:42 +01003568 if (t->proxy->options & PR_O_COOK_PFX) {
3569 for (delim = p3; delim < p4; delim++)
3570 if (*delim == COOKIE_DELIM)
3571 break;
3572 }
3573 else
3574 delim = p4;
3575
3576
3577 /* Here, we'll look for the first running server which supports the cookie.
3578 * This allows to share a same cookie between several servers, for example
3579 * to dedicate backup servers to specific servers only.
3580 */
3581 while (srv) {
3582 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3583 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3584 /* we found the server and it's usable */
3585 t->flags &= ~SN_CK_MASK;
3586 t->flags |= SN_CK_VALID | SN_DIRECT;
3587 t->srv = srv;
3588 break;
willy tarreau12350152005-12-18 01:03:27 +01003589 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003590 /* we found a server, but it's down */
3591 t->flags &= ~SN_CK_MASK;
3592 t->flags |= SN_CK_DOWN;
3593 }
3594 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003595 srv = srv->next;
3596 }
3597
willy tarreau0174f312005-12-18 01:02:42 +01003598 if (!srv && !(t->flags & SN_CK_DOWN)) {
3599 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003600 t->flags &= ~SN_CK_MASK;
3601 t->flags |= SN_CK_INVALID;
3602 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003603
willy tarreau0174f312005-12-18 01:02:42 +01003604 /* depending on the cookie mode, we may have to either :
3605 * - delete the complete cookie if we're in insert+indirect mode, so that
3606 * the server never sees it ;
3607 * - remove the server id from the cookie value, and tag the cookie as an
3608 * application cookie so that it does not get accidentely removed later,
3609 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003610 */
willy tarreau0174f312005-12-18 01:02:42 +01003611 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3612 buffer_replace2(req, p3, delim + 1, NULL, 0);
3613 p4 -= (delim + 1 - p3);
3614 ptr -= (delim + 1 - p3);
3615 del_cookie = del_colon = NULL;
3616 app_cookies++; /* protect the header from deletion */
3617 }
3618 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003619 (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 +01003620 del_cookie = p1;
3621 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003622 }
willy tarreau12350152005-12-18 01:03:27 +01003623 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003624 /* now we know that we must keep this cookie since it's
3625 * not ours. But if we wanted to delete our cookie
3626 * earlier, we cannot remove the complete header, but we
3627 * can remove the previous block itself.
3628 */
3629 app_cookies++;
3630
3631 if (del_cookie != NULL) {
3632 buffer_replace2(req, del_cookie, p1, NULL, 0);
3633 p4 -= (p1 - del_cookie);
3634 ptr -= (p1 - del_cookie);
3635 del_cookie = del_colon = NULL;
3636 }
willy tarreau240afa62005-12-17 13:14:35 +01003637 }
willy tarreau12350152005-12-18 01:03:27 +01003638
3639 if ((t->proxy->appsession_name != NULL) &&
3640 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3641 /* first, let's see if the cookie is our appcookie*/
3642
3643 /* Cool... it's the right one */
3644
3645 asession_temp = &local_asession;
3646
3647 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3648 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3649 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3650 return 0;
3651 }
3652
3653 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3654 asession_temp->sessid[t->proxy->appsession_len] = 0;
3655 asession_temp->serverid = NULL;
3656
3657 /* only do insert, if lookup fails */
3658 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3659 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3660 Alert("Not enough memory process_cli():asession:calloc().\n");
3661 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3662 return 0;
3663 }
3664
3665 asession_temp->sessid = local_asession.sessid;
3666 asession_temp->serverid = local_asession.serverid;
3667 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3668 }
3669 else{
3670 /* free wasted memory */
3671 pool_free_to(apools.sessid, local_asession.sessid);
3672 }
3673
3674 if (asession_temp->serverid == NULL) {
3675 Alert("Found Application Session without matching server.\n");
3676 } else {
3677 struct server *srv = t->proxy->srv;
3678 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003679 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003680 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3681 /* we found the server and it's usable */
3682 t->flags &= ~SN_CK_MASK;
3683 t->flags |= SN_CK_VALID | SN_DIRECT;
3684 t->srv = srv;
3685 break;
3686 } else {
3687 t->flags &= ~SN_CK_MASK;
3688 t->flags |= SN_CK_DOWN;
3689 }
3690 }
3691 srv = srv->next;
3692 }/* end while(srv) */
3693 }/* end else if server == NULL */
3694
3695 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003696 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003697 }
willy tarreau240afa62005-12-17 13:14:35 +01003698
willy tarreau5cbea6f2005-12-17 12:48:26 +01003699 /* we'll have to look for another cookie ... */
3700 p1 = p4;
3701 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003702
3703 /* There's no more cookie on this line.
3704 * We may have marked the last one(s) for deletion.
3705 * We must do this now in two ways :
3706 * - if there is no app cookie, we simply delete the header ;
3707 * - if there are app cookies, we must delete the end of the
3708 * string properly, including the colon/semi-colon before
3709 * the cookie name.
3710 */
3711 if (del_cookie != NULL) {
3712 if (app_cookies) {
3713 buffer_replace2(req, del_colon, ptr, NULL, 0);
3714 /* WARNING! <ptr> becomes invalid for now. If some code
3715 * below needs to rely on it before the end of the global
3716 * header loop, we need to correct it with this code :
3717 * ptr = del_colon;
3718 */
3719 }
3720 else
3721 delete_header = 1;
3722 }
3723 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003724
3725 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003726 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003727 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003728 }
willy tarreau240afa62005-12-17 13:14:35 +01003729 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3730
willy tarreau5cbea6f2005-12-17 12:48:26 +01003731 req->h = req->lr;
3732 } /* while (req->lr < req->r) */
3733
3734 /* end of header processing (even if incomplete) */
3735
willy tarreauef900ab2005-12-17 12:52:52 +01003736 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3737 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3738 * full. We cannot loop here since event_cli_read will disable it only if
3739 * req->l == rlim-data
3740 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003741 FD_SET(t->cli_fd, StaticReadEvent);
3742 if (t->proxy->clitimeout)
3743 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3744 else
3745 tv_eternity(&t->crexpire);
3746 }
3747
willy tarreaue39cd132005-12-17 13:00:18 +01003748 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003749 * won't be able to free more later, so the session will never terminate.
3750 */
willy tarreaue39cd132005-12-17 13:00:18 +01003751 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003752 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003753 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003754 if (!(t->flags & SN_ERR_MASK))
3755 t->flags |= SN_ERR_PRXCOND;
3756 if (!(t->flags & SN_FINST_MASK))
3757 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003758 return 1;
3759 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003760 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003761 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003762 tv_eternity(&t->crexpire);
3763 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003764 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003765 if (!(t->flags & SN_ERR_MASK))
3766 t->flags |= SN_ERR_CLICL;
3767 if (!(t->flags & SN_FINST_MASK))
3768 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003769 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003770 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003771 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3772
3773 /* read timeout : give up with an error message.
3774 */
3775 t->logs.status = 408;
3776 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003777 if (!(t->flags & SN_ERR_MASK))
3778 t->flags |= SN_ERR_CLITO;
3779 if (!(t->flags & SN_FINST_MASK))
3780 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003781 return 1;
3782 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003783
3784 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003785 }
3786 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003787 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003788 /* FIXME: this error handling is partly buggy because we always report
3789 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3790 * or HEADER phase. BTW, it's not logical to expire the client while
3791 * we're waiting for the server to connect.
3792 */
willy tarreau0f7af912005-12-17 12:21:26 +01003793 /* read or write error */
3794 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003795 tv_eternity(&t->crexpire);
3796 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003797 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003798 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003799 if (!(t->flags & SN_ERR_MASK))
3800 t->flags |= SN_ERR_CLICL;
3801 if (!(t->flags & SN_FINST_MASK))
3802 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003803 return 1;
3804 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003805 /* last read, or end of server write */
3806 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003807 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003808 tv_eternity(&t->crexpire);
3809 shutdown(t->cli_fd, SHUT_RD);
3810 t->cli_state = CL_STSHUTR;
3811 return 1;
3812 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003813 /* last server read and buffer empty */
3814 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003815 FD_CLR(t->cli_fd, StaticWriteEvent);
3816 tv_eternity(&t->cwexpire);
3817 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003818 /* We must ensure that the read part is still alive when switching
3819 * to shutw */
3820 FD_SET(t->cli_fd, StaticReadEvent);
3821 if (t->proxy->clitimeout)
3822 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003823 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003824 //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 +01003825 return 1;
3826 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003827 /* read timeout */
3828 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3829 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003830 tv_eternity(&t->crexpire);
3831 shutdown(t->cli_fd, SHUT_RD);
3832 t->cli_state = CL_STSHUTR;
3833 if (!(t->flags & SN_ERR_MASK))
3834 t->flags |= SN_ERR_CLITO;
3835 if (!(t->flags & SN_FINST_MASK))
3836 t->flags |= SN_FINST_D;
3837 return 1;
3838 }
3839 /* write timeout */
3840 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3841 FD_CLR(t->cli_fd, StaticWriteEvent);
3842 tv_eternity(&t->cwexpire);
3843 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003844 /* We must ensure that the read part is still alive when switching
3845 * to shutw */
3846 FD_SET(t->cli_fd, StaticReadEvent);
3847 if (t->proxy->clitimeout)
3848 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3849
willy tarreau036e1ce2005-12-17 13:46:33 +01003850 t->cli_state = CL_STSHUTW;
3851 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003852 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003853 if (!(t->flags & SN_FINST_MASK))
3854 t->flags |= SN_FINST_D;
3855 return 1;
3856 }
willy tarreau0f7af912005-12-17 12:21:26 +01003857
willy tarreauc58fc692005-12-17 14:13:08 +01003858 if (req->l >= req->rlim - req->data) {
3859 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003860 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003861 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003862 FD_CLR(t->cli_fd, StaticReadEvent);
3863 tv_eternity(&t->crexpire);
3864 }
3865 }
3866 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003867 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003868 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3869 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003870 if (!t->proxy->clitimeout ||
3871 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3872 /* If the client has no timeout, or if the server not ready yet, and we
3873 * know for sure that it can expire, then it's cleaner to disable the
3874 * timeout on the client side so that too low values cannot make the
3875 * sessions abort too early.
3876 */
willy tarreau0f7af912005-12-17 12:21:26 +01003877 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003878 else
3879 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003880 }
3881 }
3882
3883 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003884 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003885 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3886 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3887 tv_eternity(&t->cwexpire);
3888 }
3889 }
3890 else { /* buffer not empty */
3891 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3892 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003893 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003894 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003895 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3896 t->crexpire = t->cwexpire;
3897 }
willy tarreau0f7af912005-12-17 12:21:26 +01003898 else
3899 tv_eternity(&t->cwexpire);
3900 }
3901 }
3902 return 0; /* other cases change nothing */
3903 }
3904 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003905 if (t->res_cw == RES_ERROR) {
3906 tv_eternity(&t->cwexpire);
3907 fd_delete(t->cli_fd);
3908 t->cli_state = CL_STCLOSE;
3909 if (!(t->flags & SN_ERR_MASK))
3910 t->flags |= SN_ERR_CLICL;
3911 if (!(t->flags & SN_FINST_MASK))
3912 t->flags |= SN_FINST_D;
3913 return 1;
3914 }
3915 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003916 tv_eternity(&t->cwexpire);
3917 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003918 t->cli_state = CL_STCLOSE;
3919 return 1;
3920 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003921 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3922 tv_eternity(&t->cwexpire);
3923 fd_delete(t->cli_fd);
3924 t->cli_state = CL_STCLOSE;
3925 if (!(t->flags & SN_ERR_MASK))
3926 t->flags |= SN_ERR_CLITO;
3927 if (!(t->flags & SN_FINST_MASK))
3928 t->flags |= SN_FINST_D;
3929 return 1;
3930 }
willy tarreau0f7af912005-12-17 12:21:26 +01003931 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003932 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003933 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3934 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3935 tv_eternity(&t->cwexpire);
3936 }
3937 }
3938 else { /* buffer not empty */
3939 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3940 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003941 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003942 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003943 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3944 t->crexpire = t->cwexpire;
3945 }
willy tarreau0f7af912005-12-17 12:21:26 +01003946 else
3947 tv_eternity(&t->cwexpire);
3948 }
3949 }
3950 return 0;
3951 }
3952 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003953 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003954 tv_eternity(&t->crexpire);
3955 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003956 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003957 if (!(t->flags & SN_ERR_MASK))
3958 t->flags |= SN_ERR_CLICL;
3959 if (!(t->flags & SN_FINST_MASK))
3960 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003961 return 1;
3962 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003963 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3964 tv_eternity(&t->crexpire);
3965 fd_delete(t->cli_fd);
3966 t->cli_state = CL_STCLOSE;
3967 return 1;
3968 }
3969 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3970 tv_eternity(&t->crexpire);
3971 fd_delete(t->cli_fd);
3972 t->cli_state = CL_STCLOSE;
3973 if (!(t->flags & SN_ERR_MASK))
3974 t->flags |= SN_ERR_CLITO;
3975 if (!(t->flags & SN_FINST_MASK))
3976 t->flags |= SN_FINST_D;
3977 return 1;
3978 }
willy tarreauef900ab2005-12-17 12:52:52 +01003979 else if (req->l >= req->rlim - req->data) {
3980 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01003981
3982 /* FIXME-20050705: is it possible for a client to maintain a session
3983 * after the timeout by sending more data after it receives a close ?
3984 */
3985
willy tarreau0f7af912005-12-17 12:21:26 +01003986 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003987 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003988 FD_CLR(t->cli_fd, StaticReadEvent);
3989 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003990 //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 +01003991 }
3992 }
3993 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003994 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003995 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3996 FD_SET(t->cli_fd, StaticReadEvent);
3997 if (t->proxy->clitimeout)
3998 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3999 else
4000 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004001 //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 +01004002 }
4003 }
4004 return 0;
4005 }
4006 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004007 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004008 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004009 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 +01004010 write(1, trash, len);
4011 }
4012 return 0;
4013 }
4014 return 0;
4015}
4016
4017
4018/*
4019 * manages the server FSM and its socket. It returns 1 if a state has changed
4020 * (and a resync may be needed), 0 else.
4021 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004022int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004023 int s = t->srv_state;
4024 int c = t->cli_state;
4025 struct buffer *req = t->req;
4026 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004027 appsess *asession_temp = NULL;
4028 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004029 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004030
willy tarreau750a4722005-12-17 13:21:24 +01004031#ifdef DEBUG_FULL
4032 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4033#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004034 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4035 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4036 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4037 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004038 if (s == SV_STIDLE) {
4039 if (c == CL_STHEADERS)
4040 return 0; /* stay in idle, waiting for data to reach the client side */
4041 else if (c == CL_STCLOSE ||
4042 c == CL_STSHUTW ||
4043 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4044 tv_eternity(&t->cnexpire);
4045 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004046 if (!(t->flags & SN_ERR_MASK))
4047 t->flags |= SN_ERR_CLICL;
4048 if (!(t->flags & SN_FINST_MASK))
4049 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004050 return 1;
4051 }
4052 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01004053 /* initiate a connection to the server */
4054 conn_err = connect_server(t);
4055 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004056 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4057 t->srv_state = SV_STCONN;
4058 }
4059 else { /* try again */
4060 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004061 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004062 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004063 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004064 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4065 t->flags &= ~SN_CK_MASK;
4066 t->flags |= SN_CK_DOWN;
4067 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004068 }
4069
willy tarreaub1285d52005-12-18 01:20:14 +01004070 conn_err = connect_server(t);
4071 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004072 t->srv_state = SV_STCONN;
4073 break;
4074 }
4075 }
4076 if (t->conn_retries < 0) {
4077 /* if conn_retries < 0 or other error, let's abort */
4078 tv_eternity(&t->cnexpire);
4079 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004080 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004081 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004082 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004083 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004084 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004085 if (!(t->flags & SN_FINST_MASK))
4086 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004087 }
4088 }
4089 return 1;
4090 }
4091 }
4092 else if (s == SV_STCONN) { /* connection in progress */
4093 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004094 //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 +01004095 return 0; /* nothing changed */
4096 }
4097 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4098 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4099 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004100 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004101 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004102 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004103 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004104 if (t->conn_retries >= 0) {
4105 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004106 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004107 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004108 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4109 t->flags &= ~SN_CK_MASK;
4110 t->flags |= SN_CK_DOWN;
4111 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004112 }
willy tarreaub1285d52005-12-18 01:20:14 +01004113 conn_err = connect_server(t);
4114 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004115 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004116 }
willy tarreaub1285d52005-12-18 01:20:14 +01004117 else if (t->res_sw == RES_SILENT)
4118 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4119 else
4120 conn_err = SN_ERR_SRVCL; // it was a connect error.
4121
willy tarreau0f7af912005-12-17 12:21:26 +01004122 /* if conn_retries < 0 or other error, let's abort */
4123 tv_eternity(&t->cnexpire);
4124 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004125 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004126 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004127 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004128 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004129 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004130 if (!(t->flags & SN_FINST_MASK))
4131 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004132 return 1;
4133 }
4134 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004135 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004136
willy tarreau0f7af912005-12-17 12:21:26 +01004137 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004138 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004139 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004140 tv_eternity(&t->swexpire);
4141 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004142 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004143 if (t->proxy->srvtimeout) {
4144 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4145 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4146 t->srexpire = t->swexpire;
4147 }
4148 else
4149 tv_eternity(&t->swexpire);
4150 }
willy tarreau0f7af912005-12-17 12:21:26 +01004151
4152 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4153 FD_SET(t->srv_fd, StaticReadEvent);
4154 if (t->proxy->srvtimeout)
4155 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4156 else
4157 tv_eternity(&t->srexpire);
4158
4159 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004160 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004161
4162 /* if the user wants to log as soon as possible, without counting
4163 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004164 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004165 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4166 sess_log(t);
4167 }
willy tarreau0f7af912005-12-17 12:21:26 +01004168 }
willy tarreauef900ab2005-12-17 12:52:52 +01004169 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004170 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004171 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4172 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004173 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004174 return 1;
4175 }
4176 }
4177 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004178 /* now parse the partial (or complete) headers */
4179 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4180 char *ptr;
4181 int delete_header;
4182
4183 ptr = rep->lr;
4184
4185 /* look for the end of the current header */
4186 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4187 ptr++;
4188
4189 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004190 int line, len;
4191
4192 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004193
4194 /* first, we'll block if security checks have caught nasty things */
4195 if (t->flags & SN_CACHEABLE) {
4196 if ((t->flags & SN_CACHE_COOK) &&
4197 (t->flags & SN_SCK_ANY) &&
4198 (t->proxy->options & PR_O_CHK_CACHE)) {
4199
4200 /* we're in presence of a cacheable response containing
4201 * a set-cookie header. We'll block it as requested by
4202 * the 'checkcache' option, and send an alert.
4203 */
4204 tv_eternity(&t->srexpire);
4205 tv_eternity(&t->swexpire);
4206 fd_delete(t->srv_fd);
4207 t->srv_state = SV_STCLOSE;
4208 t->logs.status = 502;
4209 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4210 if (!(t->flags & SN_ERR_MASK))
4211 t->flags |= SN_ERR_PRXCOND;
4212 if (!(t->flags & SN_FINST_MASK))
4213 t->flags |= SN_FINST_H;
4214
4215 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4216 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4217
4218 return 1;
4219 }
4220 }
4221
willy tarreau982249e2005-12-18 00:57:06 +01004222 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4223 if (t->flags & SN_SVDENY) {
4224 tv_eternity(&t->srexpire);
4225 tv_eternity(&t->swexpire);
4226 fd_delete(t->srv_fd);
4227 t->srv_state = SV_STCLOSE;
4228 t->logs.status = 502;
4229 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4230 if (!(t->flags & SN_ERR_MASK))
4231 t->flags |= SN_ERR_PRXCOND;
4232 if (!(t->flags & SN_FINST_MASK))
4233 t->flags |= SN_FINST_H;
4234 return 1;
4235 }
4236
willy tarreau5cbea6f2005-12-17 12:48:26 +01004237 /* we'll have something else to do here : add new headers ... */
4238
willy tarreaucd878942005-12-17 13:27:43 +01004239 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4240 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004241 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004242 * insert a set-cookie here, except if we want to insert only on POST
4243 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004244 */
willy tarreau750a4722005-12-17 13:21:24 +01004245 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004246 t->proxy->cookie_name,
4247 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004248
willy tarreau036e1ce2005-12-17 13:46:33 +01004249 t->flags |= SN_SCK_INSERTED;
4250
willy tarreau750a4722005-12-17 13:21:24 +01004251 /* Here, we will tell an eventual cache on the client side that we don't
4252 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4253 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4254 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4255 */
willy tarreau240afa62005-12-17 13:14:35 +01004256 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004257 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4258 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004259
4260 if (rep->data + rep->l < rep->h)
4261 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4262 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004263 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004264 }
4265
4266 /* headers to be added */
4267 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004268 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4269 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004270 }
4271
willy tarreau25c4ea52005-12-18 00:49:49 +01004272 /* add a "connection: close" line if needed */
4273 if (t->proxy->options & PR_O_HTTP_CLOSE)
4274 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4275
willy tarreau5cbea6f2005-12-17 12:48:26 +01004276 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004277 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004278 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004279
Willy TARREAU767ba712006-03-01 22:40:50 +01004280 /* client connection already closed or option 'httpclose' required :
4281 * we close the server's outgoing connection right now.
4282 */
4283 if ((req->l == 0) &&
4284 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4285 FD_CLR(t->srv_fd, StaticWriteEvent);
4286 tv_eternity(&t->swexpire);
4287
4288 /* We must ensure that the read part is still alive when switching
4289 * to shutw */
4290 FD_SET(t->srv_fd, StaticReadEvent);
4291 if (t->proxy->srvtimeout)
4292 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4293
4294 shutdown(t->srv_fd, SHUT_WR);
4295 t->srv_state = SV_STSHUTW;
4296 }
4297
willy tarreau25c4ea52005-12-18 00:49:49 +01004298 /* if the user wants to log as soon as possible, without counting
4299 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004300 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004301 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4302 t->logs.bytes = rep->h - rep->data;
4303 sess_log(t);
4304 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004305 break;
4306 }
4307
4308 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4309 if (ptr > rep->r - 2) {
4310 /* this is a partial header, let's wait for more to come */
4311 rep->lr = ptr;
4312 break;
4313 }
4314
4315 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4316 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4317
4318 /* now we know that *ptr is either \r or \n,
4319 * and that there are at least 1 char after it.
4320 */
4321 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4322 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4323 else
4324 rep->lr = ptr + 2; /* \r\n or \n\r */
4325
4326 /*
4327 * now we know that we have a full header ; we can do whatever
4328 * we want with these pointers :
4329 * rep->h = beginning of header
4330 * ptr = end of header (first \r or \n)
4331 * rep->lr = beginning of next line (next rep->h)
4332 * rep->r = end of data (not used at this stage)
4333 */
4334
willy tarreaua1598082005-12-17 13:08:06 +01004335
willy tarreau982249e2005-12-18 00:57:06 +01004336 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004337 t->logs.logwait &= ~LW_RESP;
4338 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004339 switch (t->logs.status) {
4340 case 200:
4341 case 203:
4342 case 206:
4343 case 300:
4344 case 301:
4345 case 410:
4346 /* RFC2616 @13.4:
4347 * "A response received with a status code of
4348 * 200, 203, 206, 300, 301 or 410 MAY be stored
4349 * by a cache (...) unless a cache-control
4350 * directive prohibits caching."
4351 *
4352 * RFC2616 @9.5: POST method :
4353 * "Responses to this method are not cacheable,
4354 * unless the response includes appropriate
4355 * Cache-Control or Expires header fields."
4356 */
4357 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4358 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4359 break;
4360 default:
4361 break;
4362 }
willy tarreau4302f492005-12-18 01:00:37 +01004363 }
4364 else if (t->logs.logwait & LW_RSPHDR) {
4365 struct cap_hdr *h;
4366 int len;
4367 for (h = t->proxy->rsp_cap; h; h = h->next) {
4368 if ((h->namelen + 2 <= ptr - rep->h) &&
4369 (rep->h[h->namelen] == ':') &&
4370 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4371
4372 if (t->rsp_cap[h->index] == NULL)
4373 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4374
4375 len = ptr - (rep->h + h->namelen + 2);
4376 if (len > h->len)
4377 len = h->len;
4378
4379 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4380 t->rsp_cap[h->index][len]=0;
4381 }
4382 }
4383
willy tarreaua1598082005-12-17 13:08:06 +01004384 }
4385
willy tarreau5cbea6f2005-12-17 12:48:26 +01004386 delete_header = 0;
4387
willy tarreau982249e2005-12-18 00:57:06 +01004388 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004389 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004390 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 +01004391 max = ptr - rep->h;
4392 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004393 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004394 trash[len++] = '\n';
4395 write(1, trash, len);
4396 }
4397
willy tarreau25c4ea52005-12-18 00:49:49 +01004398 /* remove "connection: " if needed */
4399 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4400 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4401 delete_header = 1;
4402 }
4403
willy tarreau5cbea6f2005-12-17 12:48:26 +01004404 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004405 if (!delete_header && t->proxy->rsp_exp != NULL
4406 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004407 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004408 char term;
4409
4410 term = *ptr;
4411 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004412 exp = t->proxy->rsp_exp;
4413 do {
4414 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4415 switch (exp->action) {
4416 case ACT_ALLOW:
4417 if (!(t->flags & SN_SVDENY))
4418 t->flags |= SN_SVALLOW;
4419 break;
4420 case ACT_REPLACE:
4421 if (!(t->flags & SN_SVDENY)) {
4422 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4423 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4424 }
4425 break;
4426 case ACT_REMOVE:
4427 if (!(t->flags & SN_SVDENY))
4428 delete_header = 1;
4429 break;
4430 case ACT_DENY:
4431 if (!(t->flags & SN_SVALLOW))
4432 t->flags |= SN_SVDENY;
4433 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004434 case ACT_PASS: /* we simply don't deny this one */
4435 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004436 }
4437 break;
4438 }
willy tarreaue39cd132005-12-17 13:00:18 +01004439 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004440 *ptr = term; /* restore the string terminator */
4441 }
4442
willy tarreau97f58572005-12-18 00:53:44 +01004443 /* check for cache-control: or pragma: headers */
4444 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4445 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4446 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4447 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4448 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004449 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004450 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4451 else {
4452 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004453 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004454 t->flags &= ~SN_CACHE_COOK;
4455 }
4456 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004457 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004458 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004459 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004460 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4461 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004462 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004463 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004464 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4465 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4466 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4467 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4468 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4469 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004470 }
4471 }
4472 }
4473
willy tarreau5cbea6f2005-12-17 12:48:26 +01004474 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004475 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004476 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004477 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004478 char *p1, *p2, *p3, *p4;
4479
willy tarreau97f58572005-12-18 00:53:44 +01004480 t->flags |= SN_SCK_ANY;
4481
willy tarreau5cbea6f2005-12-17 12:48:26 +01004482 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4483
4484 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004485 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004486 p1++;
4487
4488 if (p1 == ptr || *p1 == ';') /* end of cookie */
4489 break;
4490
4491 /* p1 is at the beginning of the cookie name */
4492 p2 = p1;
4493
4494 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4495 p2++;
4496
4497 if (p2 == ptr || *p2 == ';') /* next cookie */
4498 break;
4499
4500 p3 = p2 + 1; /* skips the '=' sign */
4501 if (p3 == ptr)
4502 break;
4503
4504 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004505 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004506 p4++;
4507
4508 /* here, we have the cookie name between p1 and p2,
4509 * and its value between p3 and p4.
4510 * we can process it.
4511 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004512
4513 /* first, let's see if we want to capture it */
4514 if (t->proxy->capture_name != NULL &&
4515 t->logs.srv_cookie == NULL &&
4516 (p4 - p1 >= t->proxy->capture_namelen) &&
4517 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4518 int log_len = p4 - p1;
4519
4520 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4521 Alert("HTTP logging : out of memory.\n");
4522 }
4523
4524 if (log_len > t->proxy->capture_len)
4525 log_len = t->proxy->capture_len;
4526 memcpy(t->logs.srv_cookie, p1, log_len);
4527 t->logs.srv_cookie[log_len] = 0;
4528 }
4529
4530 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4531 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004532 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004533 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004534
4535 /* If the cookie is in insert mode on a known server, we'll delete
4536 * this occurrence because we'll insert another one later.
4537 * We'll delete it too if the "indirect" option is set and we're in
4538 * a direct access. */
4539 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004540 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004541 /* this header must be deleted */
4542 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004543 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004544 }
4545 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4546 /* replace bytes p3->p4 with the cookie name associated
4547 * with this server since we know it.
4548 */
4549 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004550 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004551 }
willy tarreau0174f312005-12-18 01:02:42 +01004552 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4553 /* insert the cookie name associated with this server
4554 * before existing cookie, and insert a delimitor between them..
4555 */
4556 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4557 p3[t->srv->cklen] = COOKIE_DELIM;
4558 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4559 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004560 break;
4561 }
willy tarreau12350152005-12-18 01:03:27 +01004562
4563 /* first, let's see if the cookie is our appcookie*/
4564 if ((t->proxy->appsession_name != NULL) &&
4565 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4566
4567 /* Cool... it's the right one */
4568
willy tarreaub952e1d2005-12-18 01:31:20 +01004569 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004570 asession_temp = &local_asession;
4571
willy tarreaub952e1d2005-12-18 01:31:20 +01004572 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004573 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4574 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4575 }
4576 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4577 asession_temp->sessid[t->proxy->appsession_len] = 0;
4578 asession_temp->serverid = NULL;
4579
4580 /* only do insert, if lookup fails */
4581 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4582 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4583 Alert("Not enought Memory process_srv():asession:calloc().\n");
4584 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4585 return 0;
4586 }
4587 asession_temp->sessid = local_asession.sessid;
4588 asession_temp->serverid = local_asession.serverid;
4589 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004590 }/* end if (chtbl_lookup()) */
4591 else {
willy tarreau12350152005-12-18 01:03:27 +01004592 /* free wasted memory */
4593 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004594 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004595
willy tarreaub952e1d2005-12-18 01:31:20 +01004596 if (asession_temp->serverid == NULL) {
4597 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004598 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4599 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4600 }
4601 asession_temp->serverid[0] = '\0';
4602 }
4603
willy tarreaub952e1d2005-12-18 01:31:20 +01004604 if (asession_temp->serverid[0] == '\0')
4605 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004606
4607 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4608
4609#if defined(DEBUG_HASH)
4610 print_table(&(t->proxy->htbl_proxy));
4611#endif
4612 break;
4613 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004614 else {
4615 // fprintf(stderr,"Ignoring unknown cookie : ");
4616 // write(2, p1, p2-p1);
4617 // fprintf(stderr," = ");
4618 // write(2, p3, p4-p3);
4619 // fprintf(stderr,"\n");
4620 }
4621 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4622 } /* we're now at the end of the cookie value */
4623 } /* end of cookie processing */
4624
willy tarreau97f58572005-12-18 00:53:44 +01004625 /* check for any set-cookie in case we check for cacheability */
4626 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4627 (t->proxy->options & PR_O_CHK_CACHE) &&
4628 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4629 t->flags |= SN_SCK_ANY;
4630 }
4631
willy tarreau5cbea6f2005-12-17 12:48:26 +01004632 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004633 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004634 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004635
willy tarreau5cbea6f2005-12-17 12:48:26 +01004636 rep->h = rep->lr;
4637 } /* while (rep->lr < rep->r) */
4638
4639 /* end of header processing (even if incomplete) */
4640
willy tarreauef900ab2005-12-17 12:52:52 +01004641 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4642 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4643 * full. We cannot loop here since event_srv_read will disable it only if
4644 * rep->l == rlim-data
4645 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004646 FD_SET(t->srv_fd, StaticReadEvent);
4647 if (t->proxy->srvtimeout)
4648 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4649 else
4650 tv_eternity(&t->srexpire);
4651 }
willy tarreau0f7af912005-12-17 12:21:26 +01004652
willy tarreau8337c6b2005-12-17 13:41:01 +01004653 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004654 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004655 tv_eternity(&t->srexpire);
4656 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004657 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004658 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004659 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004660 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004661 if (!(t->flags & SN_ERR_MASK))
4662 t->flags |= SN_ERR_SRVCL;
4663 if (!(t->flags & SN_FINST_MASK))
4664 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004665 return 1;
4666 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004667 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004668 * since we are in header mode, if there's no space left for headers, we
4669 * won't be able to free more later, so the session will never terminate.
4670 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004671 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 +01004672 FD_CLR(t->srv_fd, StaticReadEvent);
4673 tv_eternity(&t->srexpire);
4674 shutdown(t->srv_fd, SHUT_RD);
4675 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004676 //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 +01004677 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004678 }
4679 /* read timeout : return a 504 to the client.
4680 */
4681 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4682 tv_eternity(&t->srexpire);
4683 tv_eternity(&t->swexpire);
4684 fd_delete(t->srv_fd);
4685 t->srv_state = SV_STCLOSE;
4686 t->logs.status = 504;
4687 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004688 if (!(t->flags & SN_ERR_MASK))
4689 t->flags |= SN_ERR_SRVTO;
4690 if (!(t->flags & SN_FINST_MASK))
4691 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004692 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004693
4694 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004695 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004696 /* FIXME!!! here, we don't want to switch to SHUTW if the
4697 * client shuts read too early, because we may still have
4698 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004699 * The side-effect is that if the client completely closes its
4700 * connection during SV_STHEADER, the connection to the server
4701 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004702 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004703 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004704 FD_CLR(t->srv_fd, StaticWriteEvent);
4705 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004706
4707 /* We must ensure that the read part is still alive when switching
4708 * to shutw */
4709 FD_SET(t->srv_fd, StaticReadEvent);
4710 if (t->proxy->srvtimeout)
4711 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4712
willy tarreau0f7af912005-12-17 12:21:26 +01004713 shutdown(t->srv_fd, SHUT_WR);
4714 t->srv_state = SV_STSHUTW;
4715 return 1;
4716 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004717 /* write timeout */
4718 /* FIXME!!! here, we don't want to switch to SHUTW if the
4719 * client shuts read too early, because we may still have
4720 * some work to do on the headers.
4721 */
4722 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4723 FD_CLR(t->srv_fd, StaticWriteEvent);
4724 tv_eternity(&t->swexpire);
4725 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004726 /* We must ensure that the read part is still alive when switching
4727 * to shutw */
4728 FD_SET(t->srv_fd, StaticReadEvent);
4729 if (t->proxy->srvtimeout)
4730 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4731
4732 /* We must ensure that the read part is still alive when switching
4733 * to shutw */
4734 FD_SET(t->srv_fd, StaticReadEvent);
4735 if (t->proxy->srvtimeout)
4736 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4737
willy tarreau036e1ce2005-12-17 13:46:33 +01004738 t->srv_state = SV_STSHUTW;
4739 if (!(t->flags & SN_ERR_MASK))
4740 t->flags |= SN_ERR_SRVTO;
4741 if (!(t->flags & SN_FINST_MASK))
4742 t->flags |= SN_FINST_H;
4743 return 1;
4744 }
willy tarreau0f7af912005-12-17 12:21:26 +01004745
4746 if (req->l == 0) {
4747 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4748 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4749 tv_eternity(&t->swexpire);
4750 }
4751 }
4752 else { /* client buffer not empty */
4753 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4754 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004755 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004756 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004757 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4758 t->srexpire = t->swexpire;
4759 }
willy tarreau0f7af912005-12-17 12:21:26 +01004760 else
4761 tv_eternity(&t->swexpire);
4762 }
4763 }
4764
willy tarreau5cbea6f2005-12-17 12:48:26 +01004765 /* be nice with the client side which would like to send a complete header
4766 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4767 * would read all remaining data at once ! The client should not write past rep->lr
4768 * when the server is in header state.
4769 */
4770 //return header_processed;
4771 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004772 }
4773 else if (s == SV_STDATA) {
4774 /* read or write error */
4775 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004776 tv_eternity(&t->srexpire);
4777 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004778 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004779 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004780 if (!(t->flags & SN_ERR_MASK))
4781 t->flags |= SN_ERR_SRVCL;
4782 if (!(t->flags & SN_FINST_MASK))
4783 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004784 return 1;
4785 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004786 /* last read, or end of client write */
4787 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004788 FD_CLR(t->srv_fd, StaticReadEvent);
4789 tv_eternity(&t->srexpire);
4790 shutdown(t->srv_fd, SHUT_RD);
4791 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004792 //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 +01004793 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004794 }
4795 /* end of client read and no more data to send */
4796 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4797 FD_CLR(t->srv_fd, StaticWriteEvent);
4798 tv_eternity(&t->swexpire);
4799 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004800 /* We must ensure that the read part is still alive when switching
4801 * to shutw */
4802 FD_SET(t->srv_fd, StaticReadEvent);
4803 if (t->proxy->srvtimeout)
4804 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4805
willy tarreaua41a8b42005-12-17 14:02:24 +01004806 t->srv_state = SV_STSHUTW;
4807 return 1;
4808 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004809 /* read timeout */
4810 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4811 FD_CLR(t->srv_fd, StaticReadEvent);
4812 tv_eternity(&t->srexpire);
4813 shutdown(t->srv_fd, SHUT_RD);
4814 t->srv_state = SV_STSHUTR;
4815 if (!(t->flags & SN_ERR_MASK))
4816 t->flags |= SN_ERR_SRVTO;
4817 if (!(t->flags & SN_FINST_MASK))
4818 t->flags |= SN_FINST_D;
4819 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004820 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004821 /* write timeout */
4822 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004823 FD_CLR(t->srv_fd, StaticWriteEvent);
4824 tv_eternity(&t->swexpire);
4825 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004826 /* We must ensure that the read part is still alive when switching
4827 * to shutw */
4828 FD_SET(t->srv_fd, StaticReadEvent);
4829 if (t->proxy->srvtimeout)
4830 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004831 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004832 if (!(t->flags & SN_ERR_MASK))
4833 t->flags |= SN_ERR_SRVTO;
4834 if (!(t->flags & SN_FINST_MASK))
4835 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004836 return 1;
4837 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004838
4839 /* recompute request time-outs */
4840 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004841 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4842 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4843 tv_eternity(&t->swexpire);
4844 }
4845 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004846 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004847 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4848 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004849 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004850 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004851 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4852 t->srexpire = t->swexpire;
4853 }
willy tarreau0f7af912005-12-17 12:21:26 +01004854 else
4855 tv_eternity(&t->swexpire);
4856 }
4857 }
4858
willy tarreaub1ff9db2005-12-17 13:51:03 +01004859 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004860 if (rep->l == BUFSIZE) { /* no room to read more data */
4861 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4862 FD_CLR(t->srv_fd, StaticReadEvent);
4863 tv_eternity(&t->srexpire);
4864 }
4865 }
4866 else {
4867 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4868 FD_SET(t->srv_fd, StaticReadEvent);
4869 if (t->proxy->srvtimeout)
4870 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4871 else
4872 tv_eternity(&t->srexpire);
4873 }
4874 }
4875
4876 return 0; /* other cases change nothing */
4877 }
4878 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004879 if (t->res_sw == RES_ERROR) {
4880 //FD_CLR(t->srv_fd, StaticWriteEvent);
4881 tv_eternity(&t->swexpire);
4882 fd_delete(t->srv_fd);
4883 //close(t->srv_fd);
4884 t->srv_state = SV_STCLOSE;
4885 if (!(t->flags & SN_ERR_MASK))
4886 t->flags |= SN_ERR_SRVCL;
4887 if (!(t->flags & SN_FINST_MASK))
4888 t->flags |= SN_FINST_D;
4889 return 1;
4890 }
4891 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004892 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004893 tv_eternity(&t->swexpire);
4894 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004895 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004896 t->srv_state = SV_STCLOSE;
4897 return 1;
4898 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004899 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4900 //FD_CLR(t->srv_fd, StaticWriteEvent);
4901 tv_eternity(&t->swexpire);
4902 fd_delete(t->srv_fd);
4903 //close(t->srv_fd);
4904 t->srv_state = SV_STCLOSE;
4905 if (!(t->flags & SN_ERR_MASK))
4906 t->flags |= SN_ERR_SRVTO;
4907 if (!(t->flags & SN_FINST_MASK))
4908 t->flags |= SN_FINST_D;
4909 return 1;
4910 }
willy tarreau0f7af912005-12-17 12:21:26 +01004911 else if (req->l == 0) {
4912 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4913 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4914 tv_eternity(&t->swexpire);
4915 }
4916 }
4917 else { /* buffer not empty */
4918 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4919 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004920 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004921 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004922 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4923 t->srexpire = t->swexpire;
4924 }
willy tarreau0f7af912005-12-17 12:21:26 +01004925 else
4926 tv_eternity(&t->swexpire);
4927 }
4928 }
4929 return 0;
4930 }
4931 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004932 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004933 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004934 tv_eternity(&t->srexpire);
4935 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004936 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004937 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004938 if (!(t->flags & SN_ERR_MASK))
4939 t->flags |= SN_ERR_SRVCL;
4940 if (!(t->flags & SN_FINST_MASK))
4941 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004942 return 1;
4943 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004944 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4945 //FD_CLR(t->srv_fd, StaticReadEvent);
4946 tv_eternity(&t->srexpire);
4947 fd_delete(t->srv_fd);
4948 //close(t->srv_fd);
4949 t->srv_state = SV_STCLOSE;
4950 return 1;
4951 }
4952 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4953 //FD_CLR(t->srv_fd, StaticReadEvent);
4954 tv_eternity(&t->srexpire);
4955 fd_delete(t->srv_fd);
4956 //close(t->srv_fd);
4957 t->srv_state = SV_STCLOSE;
4958 if (!(t->flags & SN_ERR_MASK))
4959 t->flags |= SN_ERR_SRVTO;
4960 if (!(t->flags & SN_FINST_MASK))
4961 t->flags |= SN_FINST_D;
4962 return 1;
4963 }
willy tarreau0f7af912005-12-17 12:21:26 +01004964 else if (rep->l == BUFSIZE) { /* no room to read more data */
4965 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4966 FD_CLR(t->srv_fd, StaticReadEvent);
4967 tv_eternity(&t->srexpire);
4968 }
4969 }
4970 else {
4971 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4972 FD_SET(t->srv_fd, StaticReadEvent);
4973 if (t->proxy->srvtimeout)
4974 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4975 else
4976 tv_eternity(&t->srexpire);
4977 }
4978 }
4979 return 0;
4980 }
4981 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004982 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004983 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004984 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 +01004985 write(1, trash, len);
4986 }
4987 return 0;
4988 }
4989 return 0;
4990}
4991
4992
willy tarreau5cbea6f2005-12-17 12:48:26 +01004993/* Processes the client and server jobs of a session task, then
4994 * puts it back to the wait queue in a clean state, or
4995 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01004996 * the time the task accepts to wait, or TIME_ETERNITY for
4997 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01004998 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004999int process_session(struct task *t) {
5000 struct session *s = t->context;
5001 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005002
willy tarreau5cbea6f2005-12-17 12:48:26 +01005003 do {
5004 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005005 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005006 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005007 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005008 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005009 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005010 } while (fsm_resync);
5011
5012 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005013 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005014 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005015
willy tarreau5cbea6f2005-12-17 12:48:26 +01005016 tv_min(&min1, &s->crexpire, &s->cwexpire);
5017 tv_min(&min2, &s->srexpire, &s->swexpire);
5018 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005019 tv_min(&t->expire, &min1, &min2);
5020
5021 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005022 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005023
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005024#ifdef DEBUG_FULL
5025 /* DEBUG code : this should never ever happen, otherwise it indicates
5026 * that a task still has something to do and will provoke a quick loop.
5027 */
5028 if (tv_remain2(&now, &t->expire) <= 0)
5029 exit(100);
5030#endif
5031
willy tarreaub952e1d2005-12-18 01:31:20 +01005032 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005033 }
5034
willy tarreau5cbea6f2005-12-17 12:48:26 +01005035 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005036 actconn--;
5037
willy tarreau982249e2005-12-18 00:57:06 +01005038 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005039 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005040 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 +01005041 write(1, trash, len);
5042 }
5043
willy tarreau750a4722005-12-17 13:21:24 +01005044 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005045 if (s->rep != NULL)
5046 s->logs.bytes = s->rep->total;
5047
willy tarreau9fe663a2005-12-17 13:02:59 +01005048 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005049 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005050 sess_log(s);
5051
willy tarreau0f7af912005-12-17 12:21:26 +01005052 /* the task MUST not be in the run queue anymore */
5053 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005054 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005055 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005056 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005057}
5058
5059
5060
5061/*
5062 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005063 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005064 */
5065int process_chk(struct task *t) {
5066 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005067 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005068 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005069
willy tarreauef900ab2005-12-17 12:52:52 +01005070 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005071
willy tarreau25424f82006-03-19 19:37:48 +01005072 new_chk:
5073 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005074 if (fd < 0) { /* no check currently running */
5075 //fprintf(stderr, "process_chk: 2\n");
5076 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5077 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005078 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005079 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005080
5081 /* we don't send any health-checks when the proxy is stopped or when
5082 * the server should not be checked.
5083 */
5084 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005085 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5086 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005087 task_queue(t); /* restore t to its place in the task list */
5088 return tv_remain2(&now, &t->expire);
5089 }
5090
willy tarreau5cbea6f2005-12-17 12:48:26 +01005091 /* we'll initiate a new check */
5092 s->result = 0; /* no result yet */
5093 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005094 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005095 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5096 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5097 //fprintf(stderr, "process_chk: 3\n");
5098
willy tarreaua41a8b42005-12-17 14:02:24 +01005099 /* we'll connect to the check port on the server */
5100 sa = s->addr;
5101 sa.sin_port = htons(s->check_port);
5102
willy tarreau0174f312005-12-18 01:02:42 +01005103 /* allow specific binding :
5104 * - server-specific at first
5105 * - proxy-specific next
5106 */
5107 if (s->state & SRV_BIND_SRC) {
5108 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5109 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5110 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5111 s->proxy->id, s->id);
5112 s->result = -1;
5113 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005114 }
willy tarreau0174f312005-12-18 01:02:42 +01005115 else if (s->proxy->options & PR_O_BIND_SRC) {
5116 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5117 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5118 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5119 s->proxy->id);
5120 s->result = -1;
5121 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005122 }
willy tarreau0174f312005-12-18 01:02:42 +01005123
5124 if (!s->result) {
5125 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5126 /* OK, connection in progress or established */
5127
5128 //fprintf(stderr, "process_chk: 4\n");
5129
5130 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5131 fdtab[fd].owner = t;
5132 fdtab[fd].read = &event_srv_chk_r;
5133 fdtab[fd].write = &event_srv_chk_w;
5134 fdtab[fd].state = FD_STCONN; /* connection in progress */
5135 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005136#ifdef DEBUG_FULL
5137 assert (!FD_ISSET(fd, StaticReadEvent));
5138#endif
willy tarreau0174f312005-12-18 01:02:42 +01005139 fd_insert(fd);
5140 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5141 tv_delayfrom(&t->expire, &now, s->inter);
5142 task_queue(t); /* restore t to its place in the task list */
5143 return tv_remain(&now, &t->expire);
5144 }
5145 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5146 s->result = -1; /* a real error */
5147 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005148 }
5149 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005150 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005151 }
5152
5153 if (!s->result) { /* nothing done */
5154 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005155 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5156 tv_delayfrom(&t->expire, &t->expire, s->inter);
5157 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005158 }
5159
5160 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005161 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005162 s->health--; /* still good */
5163 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005164 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005165 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005166 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005167 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01005168
willy tarreaudd07e972005-12-18 00:48:48 +01005169 if (find_server(s->proxy) == NULL) {
5170 Alert("Proxy %s has no server available !\n", s->proxy->id);
5171 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5172 }
5173 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005174 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005175 }
5176
5177 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005178 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005179 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5180 tv_delayfrom(&t->expire, &t->expire, s->inter);
5181 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005182 }
5183 else {
5184 //fprintf(stderr, "process_chk: 8\n");
5185 /* there was a test running */
5186 if (s->result > 0) { /* good server detected */
5187 //fprintf(stderr, "process_chk: 9\n");
5188 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005189 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005190 if (s->health == s->rise) {
willy tarreaufd6dfe72006-03-19 19:38:19 +01005191 Warning("Server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005192 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005193 }
willy tarreauef900ab2005-12-17 12:52:52 +01005194
willy tarreaue47c8d72005-12-17 12:55:52 +01005195 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005196 s->state |= SRV_RUNNING;
5197 }
willy tarreauef900ab2005-12-17 12:52:52 +01005198 s->curfd = -1; /* no check running anymore */
5199 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005200 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005201 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5202 tv_delayfrom(&t->expire, &t->expire, s->inter);
5203 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005204 }
5205 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5206 //fprintf(stderr, "process_chk: 10\n");
5207 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005208 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005209 s->health--; /* still good */
5210 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005211 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005212
willy tarreaudd07e972005-12-18 00:48:48 +01005213 if (s->health == s->rise) {
5214 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005215 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01005216
5217 if (find_server(s->proxy) == NULL) {
5218 Alert("Proxy %s has no server available !\n", s->proxy->id);
5219 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5220 }
willy tarreau535ae7a2005-12-17 12:58:00 +01005221 }
willy tarreauef900ab2005-12-17 12:52:52 +01005222
willy tarreau5cbea6f2005-12-17 12:48:26 +01005223 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005224 }
5225 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005226 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005227 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005228 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5229 tv_delayfrom(&t->expire, &t->expire, s->inter);
5230 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005231 }
5232 /* if result is 0 and there's no timeout, we have to wait again */
5233 }
5234 //fprintf(stderr, "process_chk: 11\n");
5235 s->result = 0;
5236 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005237 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005238}
5239
5240
willy tarreau5cbea6f2005-12-17 12:48:26 +01005241
willy tarreau0f7af912005-12-17 12:21:26 +01005242#if STATTIME > 0
5243int stats(void);
5244#endif
5245
5246/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005247 * This does 4 things :
5248 * - wake up all expired tasks
5249 * - call all runnable tasks
5250 * - call maintain_proxies() to enable/disable the listeners
5251 * - return the delay till next event in ms, -1 = wait indefinitely
5252 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5253 *
willy tarreau0f7af912005-12-17 12:21:26 +01005254 */
5255
willy tarreau1c2ad212005-12-18 01:11:29 +01005256int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005257 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005258 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005259 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005260
willy tarreaub952e1d2005-12-18 01:31:20 +01005261 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005262
willy tarreau1c2ad212005-12-18 01:11:29 +01005263 /* look for expired tasks and add them to the run queue.
5264 */
5265 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5266 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5267 tnext = t->next;
5268 if (t->state & TASK_RUNNING)
5269 continue;
5270
willy tarreaub952e1d2005-12-18 01:31:20 +01005271 if (tv_iseternity(&t->expire))
5272 continue;
5273
willy tarreau1c2ad212005-12-18 01:11:29 +01005274 /* wakeup expired entries. It doesn't matter if they are
5275 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005276 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005277 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005278 task_wakeup(&rq, t);
5279 }
5280 else {
5281 /* first non-runnable task. Use its expiration date as an upper bound */
5282 int temp_time = tv_remain(&now, &t->expire);
5283 if (temp_time)
5284 next_time = temp_time;
5285 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005286 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005287 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005288
willy tarreau1c2ad212005-12-18 01:11:29 +01005289 /* process each task in the run queue now. Each task may be deleted
5290 * since we only use tnext.
5291 */
5292 tnext = rq;
5293 while ((t = tnext) != NULL) {
5294 int temp_time;
5295
5296 tnext = t->rqnext;
5297 task_sleep(&rq, t);
5298 temp_time = t->process(t);
5299 next_time = MINTIME(temp_time, next_time);
5300 }
5301
5302 /* maintain all proxies in a consistent state. This should quickly become a task */
5303 time2 = maintain_proxies();
5304 return MINTIME(time2, next_time);
5305}
5306
5307
5308#if defined(ENABLE_EPOLL)
5309
5310/*
5311 * Main epoll() loop.
5312 */
5313
5314/* does 3 actions :
5315 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5316 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5317 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5318 *
5319 * returns 0 if initialization failed, !0 otherwise.
5320 */
5321
5322int epoll_loop(int action) {
5323 int next_time;
5324 int status;
5325 int fd;
5326
5327 int fds, count;
5328 int pr, pw, sr, sw;
5329 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5330 struct epoll_event ev;
5331
5332 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005333 static struct epoll_event *epoll_events = NULL;
5334 static int epoll_fd;
5335
5336 if (action == POLL_LOOP_ACTION_INIT) {
5337 epoll_fd = epoll_create(global.maxsock + 1);
5338 if (epoll_fd < 0)
5339 return 0;
5340 else {
5341 epoll_events = (struct epoll_event*)
5342 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5343 PrevReadEvent = (fd_set *)
5344 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5345 PrevWriteEvent = (fd_set *)
5346 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005347 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005348 return 1;
5349 }
5350 else if (action == POLL_LOOP_ACTION_CLEAN) {
5351 if (PrevWriteEvent) free(PrevWriteEvent);
5352 if (PrevReadEvent) free(PrevReadEvent);
5353 if (epoll_events) free(epoll_events);
5354 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005355 epoll_fd = 0;
5356 return 1;
5357 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005358
willy tarreau1c2ad212005-12-18 01:11:29 +01005359 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005360
willy tarreau1c2ad212005-12-18 01:11:29 +01005361 tv_now(&now);
5362
5363 while (1) {
5364 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005365
5366 /* stop when there's no connection left and we don't allow them anymore */
5367 if (!actconn && listeners == 0)
5368 break;
5369
willy tarreau0f7af912005-12-17 12:21:26 +01005370#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005371 {
5372 int time2;
5373 time2 = stats();
5374 next_time = MINTIME(time2, next_time);
5375 }
willy tarreau0f7af912005-12-17 12:21:26 +01005376#endif
5377
willy tarreau1c2ad212005-12-18 01:11:29 +01005378 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5379
5380 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5381 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5382
5383 if ((ro^rn) | (wo^wn)) {
5384 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5385#define FDSETS_ARE_INT_ALIGNED
5386#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005387
willy tarreauad90a0c2005-12-18 01:09:15 +01005388#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5389#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005390 pr = (ro >> count) & 1;
5391 pw = (wo >> count) & 1;
5392 sr = (rn >> count) & 1;
5393 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005394#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005395 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5396 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5397 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5398 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005399#endif
5400#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005401 pr = FD_ISSET(fd, PrevReadEvent);
5402 pw = FD_ISSET(fd, PrevWriteEvent);
5403 sr = FD_ISSET(fd, StaticReadEvent);
5404 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005405#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005406 if (!((sr^pr) | (sw^pw)))
5407 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005408
willy tarreau1c2ad212005-12-18 01:11:29 +01005409 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5410 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005411
willy tarreaub952e1d2005-12-18 01:31:20 +01005412#ifdef EPOLL_CTL_MOD_WORKAROUND
5413 /* I encountered a rarely reproducible problem with
5414 * EPOLL_CTL_MOD where a modified FD (systematically
5415 * the one in epoll_events[0], fd#7) would sometimes
5416 * be set EPOLL_OUT while asked for a read ! This is
5417 * with the 2.4 epoll patch. The workaround is to
5418 * delete then recreate in case of modification.
5419 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5420 * nor RHEL kernels.
5421 */
5422
5423 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5424 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5425
5426 if ((sr | sw))
5427 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5428#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005429 if ((pr | pw)) {
5430 /* the file-descriptor already exists... */
5431 if ((sr | sw)) {
5432 /* ...and it will still exist */
5433 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5434 // perror("epoll_ctl(MOD)");
5435 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005436 }
5437 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005438 /* ...and it will be removed */
5439 if (fdtab[fd].state != FD_STCLOSE &&
5440 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5441 // perror("epoll_ctl(DEL)");
5442 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005443 }
5444 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005445 } else {
5446 /* the file-descriptor did not exist, let's add it */
5447 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5448 // perror("epoll_ctl(ADD)");
5449 // exit(1);
5450 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005451 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005452#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005453 }
5454 ((int*)PrevReadEvent)[fds] = rn;
5455 ((int*)PrevWriteEvent)[fds] = wn;
5456 }
5457 }
5458
5459 /* now let's wait for events */
5460 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5461 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005462
willy tarreau1c2ad212005-12-18 01:11:29 +01005463 for (count = 0; count < status; count++) {
5464 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01005465
5466 if (FD_ISSET(fd, StaticReadEvent)) {
5467 if (fdtab[fd].state == FD_STCLOSE)
5468 continue;
5469 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5470 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005471 }
willy tarreau05be12b2006-03-19 19:35:00 +01005472
5473 if (FD_ISSET(fd, StaticWriteEvent)) {
5474 if (fdtab[fd].state == FD_STCLOSE)
5475 continue;
5476 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5477 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005478 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005479 }
5480 }
5481 return 1;
5482}
5483#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005484
willy tarreauad90a0c2005-12-18 01:09:15 +01005485
willy tarreau5cbea6f2005-12-17 12:48:26 +01005486
willy tarreau1c2ad212005-12-18 01:11:29 +01005487#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005488
willy tarreau1c2ad212005-12-18 01:11:29 +01005489/*
5490 * Main poll() loop.
5491 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005492
willy tarreau1c2ad212005-12-18 01:11:29 +01005493/* does 3 actions :
5494 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5495 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5496 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5497 *
5498 * returns 0 if initialization failed, !0 otherwise.
5499 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005500
willy tarreau1c2ad212005-12-18 01:11:29 +01005501int poll_loop(int action) {
5502 int next_time;
5503 int status;
5504 int fd, nbfd;
5505
5506 int fds, count;
5507 int sr, sw;
5508 unsigned rn, wn; /* read new, write new */
5509
5510 /* private data */
5511 static struct pollfd *poll_events = NULL;
5512
5513 if (action == POLL_LOOP_ACTION_INIT) {
5514 poll_events = (struct pollfd*)
5515 calloc(1, sizeof(struct pollfd) * global.maxsock);
5516 return 1;
5517 }
5518 else if (action == POLL_LOOP_ACTION_CLEAN) {
5519 if (poll_events)
5520 free(poll_events);
5521 return 1;
5522 }
5523
5524 /* OK, it's POLL_LOOP_ACTION_RUN */
5525
5526 tv_now(&now);
5527
5528 while (1) {
5529 next_time = process_runnable_tasks();
5530
5531 /* stop when there's no connection left and we don't allow them anymore */
5532 if (!actconn && listeners == 0)
5533 break;
5534
5535#if STATTIME > 0
5536 {
5537 int time2;
5538 time2 = stats();
5539 next_time = MINTIME(time2, next_time);
5540 }
5541#endif
5542
5543
5544 nbfd = 0;
5545 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5546
5547 rn = ((int*)StaticReadEvent)[fds];
5548 wn = ((int*)StaticWriteEvent)[fds];
5549
5550 if ((rn|wn)) {
5551 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5552#define FDSETS_ARE_INT_ALIGNED
5553#ifdef FDSETS_ARE_INT_ALIGNED
5554
5555#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5556#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5557 sr = (rn >> count) & 1;
5558 sw = (wn >> count) & 1;
5559#else
5560 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5561 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5562#endif
5563#else
5564 sr = FD_ISSET(fd, StaticReadEvent);
5565 sw = FD_ISSET(fd, StaticWriteEvent);
5566#endif
5567 if ((sr|sw)) {
5568 poll_events[nbfd].fd = fd;
5569 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5570 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005571 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005572 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005573 }
5574 }
5575
5576 /* now let's wait for events */
5577 status = poll(poll_events, nbfd, next_time);
5578 tv_now(&now);
5579
5580 for (count = 0; status > 0 && count < nbfd; count++) {
5581 fd = poll_events[count].fd;
5582
5583 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5584 continue;
5585
5586 /* ok, we found one active fd */
5587 status--;
5588
willy tarreau05be12b2006-03-19 19:35:00 +01005589 if (FD_ISSET(fd, StaticReadEvent)) {
5590 if (fdtab[fd].state == FD_STCLOSE)
5591 continue;
5592 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5593 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005594 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005595
willy tarreau05be12b2006-03-19 19:35:00 +01005596 if (FD_ISSET(fd, StaticWriteEvent)) {
5597 if (fdtab[fd].state == FD_STCLOSE)
5598 continue;
5599 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5600 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005601 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005602 }
5603 }
5604 return 1;
5605}
willy tarreauad90a0c2005-12-18 01:09:15 +01005606#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005607
willy tarreauad90a0c2005-12-18 01:09:15 +01005608
willy tarreauad90a0c2005-12-18 01:09:15 +01005609
willy tarreau1c2ad212005-12-18 01:11:29 +01005610/*
5611 * Main select() loop.
5612 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005613
willy tarreau1c2ad212005-12-18 01:11:29 +01005614/* does 3 actions :
5615 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5616 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5617 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5618 *
5619 * returns 0 if initialization failed, !0 otherwise.
5620 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005621
willy tarreauad90a0c2005-12-18 01:09:15 +01005622
willy tarreau1c2ad212005-12-18 01:11:29 +01005623int select_loop(int action) {
5624 int next_time;
5625 int status;
5626 int fd,i;
5627 struct timeval delta;
5628 int readnotnull, writenotnull;
5629 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005630
willy tarreau1c2ad212005-12-18 01:11:29 +01005631 if (action == POLL_LOOP_ACTION_INIT) {
5632 ReadEvent = (fd_set *)
5633 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5634 WriteEvent = (fd_set *)
5635 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5636 return 1;
5637 }
5638 else if (action == POLL_LOOP_ACTION_CLEAN) {
5639 if (WriteEvent) free(WriteEvent);
5640 if (ReadEvent) free(ReadEvent);
5641 return 1;
5642 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005643
willy tarreau1c2ad212005-12-18 01:11:29 +01005644 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005645
willy tarreau1c2ad212005-12-18 01:11:29 +01005646 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005647
willy tarreau1c2ad212005-12-18 01:11:29 +01005648 while (1) {
5649 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005650
willy tarreau1c2ad212005-12-18 01:11:29 +01005651 /* stop when there's no connection left and we don't allow them anymore */
5652 if (!actconn && listeners == 0)
5653 break;
5654
5655#if STATTIME > 0
5656 {
5657 int time2;
5658 time2 = stats();
5659 next_time = MINTIME(time2, next_time);
5660 }
5661#endif
5662
willy tarreau1c2ad212005-12-18 01:11:29 +01005663 if (next_time > 0) { /* FIXME */
5664 /* Convert to timeval */
5665 /* to avoid eventual select loops due to timer precision */
5666 next_time += SCHEDULER_RESOLUTION;
5667 delta.tv_sec = next_time / 1000;
5668 delta.tv_usec = (next_time % 1000) * 1000;
5669 }
5670 else if (next_time == 0) { /* allow select to return immediately when needed */
5671 delta.tv_sec = delta.tv_usec = 0;
5672 }
5673
5674
5675 /* let's restore fdset state */
5676
5677 readnotnull = 0; writenotnull = 0;
5678 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5679 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5680 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5681 }
5682
5683 // /* just a verification code, needs to be removed for performance */
5684 // for (i=0; i<maxfd; i++) {
5685 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5686 // abort();
5687 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5688 // abort();
5689 //
5690 // }
5691
5692 status = select(maxfd,
5693 readnotnull ? ReadEvent : NULL,
5694 writenotnull ? WriteEvent : NULL,
5695 NULL,
5696 (next_time >= 0) ? &delta : NULL);
5697
5698 /* this is an experiment on the separation of the select work */
5699 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5700 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5701
5702 tv_now(&now);
5703
5704 if (status > 0) { /* must proceed with events */
5705
5706 int fds;
5707 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005708
willy tarreau1c2ad212005-12-18 01:11:29 +01005709 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5710 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5711 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5712
5713 /* if we specify read first, the accepts and zero reads will be
5714 * seen first. Moreover, system buffers will be flushed faster.
5715 */
willy tarreau05be12b2006-03-19 19:35:00 +01005716 if (FD_ISSET(fd, ReadEvent)) {
5717 if (fdtab[fd].state == FD_STCLOSE)
5718 continue;
5719 fdtab[fd].read(fd);
5720 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005721
willy tarreau05be12b2006-03-19 19:35:00 +01005722 if (FD_ISSET(fd, WriteEvent)) {
5723 if (fdtab[fd].state == FD_STCLOSE)
5724 continue;
5725 fdtab[fd].write(fd);
5726 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005727 }
5728 }
5729 else {
5730 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005731 }
willy tarreau0f7af912005-12-17 12:21:26 +01005732 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005733 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005734}
5735
5736
5737#if STATTIME > 0
5738/*
5739 * Display proxy statistics regularly. It is designed to be called from the
5740 * select_loop().
5741 */
5742int stats(void) {
5743 static int lines;
5744 static struct timeval nextevt;
5745 static struct timeval lastevt;
5746 static struct timeval starttime = {0,0};
5747 unsigned long totaltime, deltatime;
5748 int ret;
5749
willy tarreau750a4722005-12-17 13:21:24 +01005750 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005751 deltatime = (tv_diff(&lastevt, &now)?:1);
5752 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005753
willy tarreau9fe663a2005-12-17 13:02:59 +01005754 if (global.mode & MODE_STATS) {
5755 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005756 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005757 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5758 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005759 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005760 actconn, totalconn,
5761 stats_tsk_new, stats_tsk_good,
5762 stats_tsk_left, stats_tsk_right,
5763 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5764 }
5765 }
5766
5767 tv_delayfrom(&nextevt, &now, STATTIME);
5768
5769 lastevt=now;
5770 }
5771 ret = tv_remain(&now, &nextevt);
5772 return ret;
5773}
5774#endif
5775
5776
5777/*
5778 * this function enables proxies when there are enough free sessions,
5779 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005780 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005781 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005782 */
5783static int maintain_proxies(void) {
5784 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005785 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005786 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005787
5788 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005789 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005790
5791 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005792 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005793 while (p) {
5794 if (p->nbconn < p->maxconn) {
5795 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005796 for (l = p->listen; l != NULL; l = l->next) {
5797 FD_SET(l->fd, StaticReadEvent);
5798 }
willy tarreau0f7af912005-12-17 12:21:26 +01005799 p->state = PR_STRUN;
5800 }
5801 }
5802 else {
5803 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005804 for (l = p->listen; l != NULL; l = l->next) {
5805 FD_CLR(l->fd, StaticReadEvent);
5806 }
willy tarreau0f7af912005-12-17 12:21:26 +01005807 p->state = PR_STIDLE;
5808 }
5809 }
5810 p = p->next;
5811 }
5812 }
5813 else { /* block all proxies */
5814 while (p) {
5815 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005816 for (l = p->listen; l != NULL; l = l->next) {
5817 FD_CLR(l->fd, StaticReadEvent);
5818 }
willy tarreau0f7af912005-12-17 12:21:26 +01005819 p->state = PR_STIDLE;
5820 }
5821 p = p->next;
5822 }
5823 }
5824
willy tarreau5cbea6f2005-12-17 12:48:26 +01005825 if (stopping) {
5826 p = proxy;
5827 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01005828 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005829 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01005830 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005831 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005832 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005833 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005834
willy tarreaua41a8b42005-12-17 14:02:24 +01005835 for (l = p->listen; l != NULL; l = l->next) {
5836 fd_delete(l->fd);
5837 listeners--;
5838 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01005839 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005840 }
5841 else {
5842 tleft = MINTIME(t, tleft);
5843 }
5844 }
5845 p = p->next;
5846 }
5847 }
5848 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01005849}
5850
5851/*
5852 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01005853 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
5854 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01005855 */
5856static void soft_stop(void) {
5857 struct proxy *p;
5858
5859 stopping = 1;
5860 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005861 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01005862 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01005863 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005864 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01005865 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01005866 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01005867 }
willy tarreau0f7af912005-12-17 12:21:26 +01005868 p = p->next;
5869 }
5870}
5871
willy tarreaudbd3bef2006-01-20 19:35:18 +01005872static void pause_proxy(struct proxy *p) {
5873 struct listener *l;
5874 for (l = p->listen; l != NULL; l = l->next) {
5875 shutdown(l->fd, SHUT_RD);
5876 FD_CLR(l->fd, StaticReadEvent);
5877 p->state = PR_STPAUSED;
5878 }
5879}
5880
5881/*
5882 * This function temporarily disables listening so that another new instance
5883 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01005884 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01005885 * the proxy, or a SIGTTIN can be sent to listen again.
5886 */
5887static void pause_proxies(void) {
5888 struct proxy *p;
5889
5890 p = proxy;
5891 tv_now(&now); /* else, the old time before select will be used */
5892 while (p) {
5893 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
5894 Warning("Pausing proxy %s.\n", p->id);
5895 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
5896 pause_proxy(p);
5897 }
5898 p = p->next;
5899 }
5900}
5901
5902
5903/*
5904 * This function reactivates listening. This can be used after a call to
5905 * sig_pause(), for example when a new instance has failed starting up.
5906 * It is designed to be called upon reception of a SIGTTIN.
5907 */
5908static void listen_proxies(void) {
5909 struct proxy *p;
5910 struct listener *l;
5911
5912 p = proxy;
5913 tv_now(&now); /* else, the old time before select will be used */
5914 while (p) {
5915 if (p->state == PR_STPAUSED) {
5916 Warning("Enabling proxy %s.\n", p->id);
5917 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
5918
5919 for (l = p->listen; l != NULL; l = l->next) {
5920 if (listen(l->fd, p->maxconn) == 0) {
5921 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
5922 FD_SET(l->fd, StaticReadEvent);
5923 p->state = PR_STRUN;
5924 }
5925 else
5926 p->state = PR_STIDLE;
5927 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01005928 int port;
5929
5930 if (l->addr.ss_family == AF_INET6)
5931 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
5932 else
5933 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
5934
willy tarreaudbd3bef2006-01-20 19:35:18 +01005935 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01005936 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01005937 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01005938 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01005939 /* Another port might have been enabled. Let's stop everything. */
5940 pause_proxy(p);
5941 break;
5942 }
5943 }
5944 }
5945 p = p->next;
5946 }
5947}
5948
5949
willy tarreau0f7af912005-12-17 12:21:26 +01005950/*
5951 * upon SIGUSR1, let's have a soft stop.
5952 */
5953void sig_soft_stop(int sig) {
5954 soft_stop();
5955 signal(sig, SIG_IGN);
5956}
5957
willy tarreaudbd3bef2006-01-20 19:35:18 +01005958/*
5959 * upon SIGTTOU, we pause everything
5960 */
5961void sig_pause(int sig) {
5962 pause_proxies();
5963 signal(sig, sig_pause);
5964}
willy tarreau0f7af912005-12-17 12:21:26 +01005965
willy tarreau8337c6b2005-12-17 13:41:01 +01005966/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01005967 * upon SIGTTIN, let's have a soft stop.
5968 */
5969void sig_listen(int sig) {
5970 listen_proxies();
5971 signal(sig, sig_listen);
5972}
5973
5974/*
willy tarreau8337c6b2005-12-17 13:41:01 +01005975 * this function dumps every server's state when the process receives SIGHUP.
5976 */
5977void sig_dump_state(int sig) {
5978 struct proxy *p = proxy;
5979
5980 Warning("SIGHUP received, dumping servers states.\n");
5981 while (p) {
5982 struct server *s = p->srv;
5983
5984 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
5985 while (s) {
5986 if (s->state & SRV_RUNNING) {
willy tarreaufd6dfe72006-03-19 19:38:19 +01005987 Warning("SIGHUP: Server %s/%s is UP.\n", p->id, s->id);
5988 send_log(p, LOG_NOTICE, "SIGUP: Server %s/%s is UP.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01005989 }
5990 else {
willy tarreaufd6dfe72006-03-19 19:38:19 +01005991 Warning("SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
5992 send_log(p, LOG_NOTICE, "SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01005993 }
5994 s = s->next;
5995 }
willy tarreaudd07e972005-12-18 00:48:48 +01005996
5997 if (find_server(p) == NULL) {
willy tarreau1fb34932006-03-23 11:22:10 +01005998 Warning("SIGHUP: Proxy %s has no server available !\n", p->id);
5999 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s has no server available !\n", p->id);
willy tarreaudd07e972005-12-18 00:48:48 +01006000 }
6001
willy tarreau8337c6b2005-12-17 13:41:01 +01006002 p = p->next;
6003 }
6004 signal(sig, sig_dump_state);
6005}
6006
willy tarreau0f7af912005-12-17 12:21:26 +01006007void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006008 struct task *t, *tnext;
6009 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006010
willy tarreau5cbea6f2005-12-17 12:48:26 +01006011 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
6012 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
6013 tnext = t->next;
6014 s = t->context;
6015 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6016 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6017 "req=%d, rep=%d, clifd=%d\n",
6018 s, tv_remain(&now, &t->expire),
6019 s->cli_state,
6020 s->srv_state,
6021 FD_ISSET(s->cli_fd, StaticReadEvent),
6022 FD_ISSET(s->cli_fd, StaticWriteEvent),
6023 FD_ISSET(s->srv_fd, StaticReadEvent),
6024 FD_ISSET(s->srv_fd, StaticWriteEvent),
6025 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6026 );
willy tarreau0f7af912005-12-17 12:21:26 +01006027 }
willy tarreau12350152005-12-18 01:03:27 +01006028}
6029
willy tarreau64a3cc32005-12-18 01:13:11 +01006030#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006031static void fast_stop(void)
6032{
6033 struct proxy *p;
6034 p = proxy;
6035 while (p) {
6036 p->grace = 0;
6037 p = p->next;
6038 }
6039 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006040}
6041
willy tarreau12350152005-12-18 01:03:27 +01006042void sig_int(int sig) {
6043 /* This would normally be a hard stop,
6044 but we want to be sure about deallocation,
6045 and so on, so we do a soft stop with
6046 0 GRACE time
6047 */
6048 fast_stop();
6049 /* If we are killed twice, we decide to die*/
6050 signal(sig, SIG_DFL);
6051}
6052
6053void sig_term(int sig) {
6054 /* This would normally be a hard stop,
6055 but we want to be sure about deallocation,
6056 and so on, so we do a soft stop with
6057 0 GRACE time
6058 */
6059 fast_stop();
6060 /* If we are killed twice, we decide to die*/
6061 signal(sig, SIG_DFL);
6062}
willy tarreau64a3cc32005-12-18 01:13:11 +01006063#endif
willy tarreau12350152005-12-18 01:03:27 +01006064
willy tarreauc1f47532005-12-18 01:08:26 +01006065/* returns the pointer to an error in the replacement string, or NULL if OK */
6066char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006067 struct hdr_exp *exp;
6068
willy tarreauc1f47532005-12-18 01:08:26 +01006069 if (replace != NULL) {
6070 char *err;
6071 err = check_replace_string(replace);
6072 if (err)
6073 return err;
6074 }
6075
willy tarreaue39cd132005-12-17 13:00:18 +01006076 while (*head != NULL)
6077 head = &(*head)->next;
6078
6079 exp = calloc(1, sizeof(struct hdr_exp));
6080
6081 exp->preg = preg;
6082 exp->replace = replace;
6083 exp->action = action;
6084 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006085
6086 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006087}
6088
willy tarreau9fe663a2005-12-17 13:02:59 +01006089
willy tarreau0f7af912005-12-17 12:21:26 +01006090/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006091 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006092 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006093int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006094
willy tarreau9fe663a2005-12-17 13:02:59 +01006095 if (!strcmp(args[0], "global")) { /* new section */
6096 /* no option, nothing special to do */
6097 return 0;
6098 }
6099 else if (!strcmp(args[0], "daemon")) {
6100 global.mode |= MODE_DAEMON;
6101 }
6102 else if (!strcmp(args[0], "debug")) {
6103 global.mode |= MODE_DEBUG;
6104 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006105 else if (!strcmp(args[0], "noepoll")) {
6106 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6107 }
6108 else if (!strcmp(args[0], "nopoll")) {
6109 cfg_polling_mechanism &= ~POLL_USE_POLL;
6110 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006111 else if (!strcmp(args[0], "quiet")) {
6112 global.mode |= MODE_QUIET;
6113 }
6114 else if (!strcmp(args[0], "stats")) {
6115 global.mode |= MODE_STATS;
6116 }
6117 else if (!strcmp(args[0], "uid")) {
6118 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006119 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006120 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006121 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006122 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006123 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006124 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006125 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006126 global.uid = atol(args[1]);
6127 }
6128 else if (!strcmp(args[0], "gid")) {
6129 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006130 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006131 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006132 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006133 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006134 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006135 return -1;
6136 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006137 global.gid = atol(args[1]);
6138 }
6139 else if (!strcmp(args[0], "nbproc")) {
6140 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006141 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006142 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006143 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006144 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006145 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006146 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006147 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006148 global.nbproc = atol(args[1]);
6149 }
6150 else if (!strcmp(args[0], "maxconn")) {
6151 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006152 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006153 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006154 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006155 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006156 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006157 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006158 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006159 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006160#ifdef SYSTEM_MAXCONN
6161 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6162 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);
6163 global.maxconn = DEFAULT_MAXCONN;
6164 }
6165#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006166 }
willy tarreaub1285d52005-12-18 01:20:14 +01006167 else if (!strcmp(args[0], "ulimit-n")) {
6168 if (global.rlimit_nofile != 0) {
6169 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6170 return 0;
6171 }
6172 if (*(args[1]) == 0) {
6173 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6174 return -1;
6175 }
6176 global.rlimit_nofile = atol(args[1]);
6177 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006178 else if (!strcmp(args[0], "chroot")) {
6179 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006180 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006181 return 0;
6182 }
6183 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006184 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006185 return -1;
6186 }
6187 global.chroot = strdup(args[1]);
6188 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006189 else if (!strcmp(args[0], "pidfile")) {
6190 if (global.pidfile != NULL) {
6191 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6192 return 0;
6193 }
6194 if (*(args[1]) == 0) {
6195 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6196 return -1;
6197 }
6198 global.pidfile = strdup(args[1]);
6199 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006200 else if (!strcmp(args[0], "log")) { /* syslog server address */
6201 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006202 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006203
6204 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006205 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006206 return -1;
6207 }
6208
6209 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6210 if (!strcmp(log_facilities[facility], args[2]))
6211 break;
6212
6213 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006214 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006215 exit(1);
6216 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006217
6218 level = 7; /* max syslog level = debug */
6219 if (*(args[3])) {
6220 while (level >= 0 && strcmp(log_levels[level], args[3]))
6221 level--;
6222 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006223 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006224 exit(1);
6225 }
6226 }
6227
willy tarreau9fe663a2005-12-17 13:02:59 +01006228 sa = str2sa(args[1]);
6229 if (!sa->sin_port)
6230 sa->sin_port = htons(SYSLOG_PORT);
6231
6232 if (global.logfac1 == -1) {
6233 global.logsrv1 = *sa;
6234 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006235 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006236 }
6237 else if (global.logfac2 == -1) {
6238 global.logsrv2 = *sa;
6239 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006240 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006241 }
6242 else {
6243 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6244 return -1;
6245 }
6246
6247 }
6248 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006249 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006250 return -1;
6251 }
6252 return 0;
6253}
6254
6255
willy tarreaua41a8b42005-12-17 14:02:24 +01006256void init_default_instance() {
6257 memset(&defproxy, 0, sizeof(defproxy));
6258 defproxy.mode = PR_MODE_TCP;
6259 defproxy.state = PR_STNEW;
6260 defproxy.maxconn = cfg_maxpconn;
6261 defproxy.conn_retries = CONN_RETRIES;
6262 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6263}
6264
willy tarreau9fe663a2005-12-17 13:02:59 +01006265/*
6266 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6267 */
6268int cfg_parse_listen(char *file, int linenum, char **args) {
6269 static struct proxy *curproxy = NULL;
6270 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006271 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006272 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006273
6274 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006275 if (!*args[1]) {
6276 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6277 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006278 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006279 return -1;
6280 }
6281
6282 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006283 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006284 return -1;
6285 }
6286 curproxy->next = proxy;
6287 proxy = curproxy;
6288 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006289
6290 /* parse the listener address if any */
6291 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006292 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006293 if (!curproxy->listen)
6294 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006295 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01006296 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006297
willy tarreau9fe663a2005-12-17 13:02:59 +01006298 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006299 curproxy->state = defproxy.state;
6300 curproxy->maxconn = defproxy.maxconn;
6301 curproxy->conn_retries = defproxy.conn_retries;
6302 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006303
6304 if (defproxy.check_req)
6305 curproxy->check_req = strdup(defproxy.check_req);
6306 curproxy->check_len = defproxy.check_len;
6307
6308 if (defproxy.cookie_name)
6309 curproxy->cookie_name = strdup(defproxy.cookie_name);
6310 curproxy->cookie_len = defproxy.cookie_len;
6311
6312 if (defproxy.capture_name)
6313 curproxy->capture_name = strdup(defproxy.capture_name);
6314 curproxy->capture_namelen = defproxy.capture_namelen;
6315 curproxy->capture_len = defproxy.capture_len;
6316
6317 if (defproxy.errmsg.msg400)
6318 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6319 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6320
6321 if (defproxy.errmsg.msg403)
6322 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6323 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6324
6325 if (defproxy.errmsg.msg408)
6326 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6327 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6328
6329 if (defproxy.errmsg.msg500)
6330 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6331 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6332
6333 if (defproxy.errmsg.msg502)
6334 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6335 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6336
6337 if (defproxy.errmsg.msg503)
6338 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6339 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6340
6341 if (defproxy.errmsg.msg504)
6342 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6343 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6344
willy tarreaua41a8b42005-12-17 14:02:24 +01006345 curproxy->clitimeout = defproxy.clitimeout;
6346 curproxy->contimeout = defproxy.contimeout;
6347 curproxy->srvtimeout = defproxy.srvtimeout;
6348 curproxy->mode = defproxy.mode;
6349 curproxy->logfac1 = defproxy.logfac1;
6350 curproxy->logsrv1 = defproxy.logsrv1;
6351 curproxy->loglev1 = defproxy.loglev1;
6352 curproxy->logfac2 = defproxy.logfac2;
6353 curproxy->logsrv2 = defproxy.logsrv2;
6354 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006355 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006356 curproxy->grace = defproxy.grace;
6357 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006358 curproxy->mon_net = defproxy.mon_net;
6359 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006360 return 0;
6361 }
6362 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006363 /* some variables may have already been initialized earlier */
6364 if (defproxy.check_req) free(defproxy.check_req);
6365 if (defproxy.cookie_name) free(defproxy.cookie_name);
6366 if (defproxy.capture_name) free(defproxy.capture_name);
6367 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6368 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6369 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6370 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6371 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6372 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6373 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6374
6375 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006376 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006377 return 0;
6378 }
6379 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006380 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006381 return -1;
6382 }
6383
willy tarreaua41a8b42005-12-17 14:02:24 +01006384 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6385 if (curproxy == &defproxy) {
6386 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6387 return -1;
6388 }
6389
6390 if (strchr(args[1], ':') == NULL) {
6391 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6392 file, linenum, args[0]);
6393 return -1;
6394 }
6395 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006396 if (!curproxy->listen)
6397 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006398 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006399 return 0;
6400 }
willy tarreaub1285d52005-12-18 01:20:14 +01006401 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6402 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6403 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6404 file, linenum, args[0]);
6405 return -1;
6406 }
6407 /* flush useless bits */
6408 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6409 return 0;
6410 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006411 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006412 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6413 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6414 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6415 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006416 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006417 return -1;
6418 }
6419 }
6420 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006421 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006422 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006423 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6424 curproxy->state = PR_STNEW;
6425 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006426 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6427 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006428// if (curproxy == &defproxy) {
6429// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6430// return -1;
6431// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006432
willy tarreau9fe663a2005-12-17 13:02:59 +01006433 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006434// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6435// file, linenum);
6436// return 0;
6437 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006438 }
6439
6440 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006441 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6442 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006443 return -1;
6444 }
6445 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006446 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006447
6448 cur_arg = 2;
6449 while (*(args[cur_arg])) {
6450 if (!strcmp(args[cur_arg], "rewrite")) {
6451 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006452 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006453 else if (!strcmp(args[cur_arg], "indirect")) {
6454 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006455 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006456 else if (!strcmp(args[cur_arg], "insert")) {
6457 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006458 }
willy tarreau240afa62005-12-17 13:14:35 +01006459 else if (!strcmp(args[cur_arg], "nocache")) {
6460 curproxy->options |= PR_O_COOK_NOC;
6461 }
willy tarreaucd878942005-12-17 13:27:43 +01006462 else if (!strcmp(args[cur_arg], "postonly")) {
6463 curproxy->options |= PR_O_COOK_POST;
6464 }
willy tarreau0174f312005-12-18 01:02:42 +01006465 else if (!strcmp(args[cur_arg], "prefix")) {
6466 curproxy->options |= PR_O_COOK_PFX;
6467 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006468 else {
willy tarreau0174f312005-12-18 01:02:42 +01006469 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006470 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006471 return -1;
6472 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006473 cur_arg++;
6474 }
willy tarreau0174f312005-12-18 01:02:42 +01006475 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6476 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6477 file, linenum);
6478 return -1;
6479 }
6480
6481 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6482 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006483 file, linenum);
6484 return -1;
6485 }
willy tarreau12350152005-12-18 01:03:27 +01006486 }/* end else if (!strcmp(args[0], "cookie")) */
6487 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6488// if (curproxy == &defproxy) {
6489// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6490// return -1;
6491// }
6492
6493 if (curproxy->appsession_name != NULL) {
6494// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6495// file, linenum);
6496// return 0;
6497 free(curproxy->appsession_name);
6498 }
6499
6500 if (*(args[5]) == 0) {
6501 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6502 file, linenum, args[0]);
6503 return -1;
6504 }
6505 have_appsession = 1;
6506 curproxy->appsession_name = strdup(args[1]);
6507 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6508 curproxy->appsession_len = atoi(args[3]);
6509 curproxy->appsession_timeout = atoi(args[5]);
6510 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6511 if (rc) {
6512 Alert("Error Init Appsession Hashtable.\n");
6513 return -1;
6514 }
6515 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006516 else if (!strcmp(args[0], "capture")) {
6517 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6518 // if (curproxy == &defproxy) {
6519 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6520 // return -1;
6521 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006522
willy tarreau4302f492005-12-18 01:00:37 +01006523 if (curproxy->capture_name != NULL) {
6524 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6525 // file, linenum, args[0]);
6526 // return 0;
6527 free(curproxy->capture_name);
6528 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006529
willy tarreau4302f492005-12-18 01:00:37 +01006530 if (*(args[4]) == 0) {
6531 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6532 file, linenum, args[0]);
6533 return -1;
6534 }
6535 curproxy->capture_name = strdup(args[2]);
6536 curproxy->capture_namelen = strlen(curproxy->capture_name);
6537 curproxy->capture_len = atol(args[4]);
6538 if (curproxy->capture_len >= CAPTURE_LEN) {
6539 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6540 file, linenum, CAPTURE_LEN - 1);
6541 curproxy->capture_len = CAPTURE_LEN - 1;
6542 }
6543 curproxy->to_log |= LW_COOKIE;
6544 }
6545 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6546 struct cap_hdr *hdr;
6547
6548 if (curproxy == &defproxy) {
6549 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6550 return -1;
6551 }
6552
6553 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6554 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6555 file, linenum, args[0], args[1]);
6556 return -1;
6557 }
6558
6559 hdr = calloc(sizeof(struct cap_hdr), 1);
6560 hdr->next = curproxy->req_cap;
6561 hdr->name = strdup(args[3]);
6562 hdr->namelen = strlen(args[3]);
6563 hdr->len = atol(args[5]);
6564 hdr->index = curproxy->nb_req_cap++;
6565 curproxy->req_cap = hdr;
6566 curproxy->to_log |= LW_REQHDR;
6567 }
6568 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6569 struct cap_hdr *hdr;
6570
6571 if (curproxy == &defproxy) {
6572 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6573 return -1;
6574 }
6575
6576 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6577 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6578 file, linenum, args[0], args[1]);
6579 return -1;
6580 }
6581 hdr = calloc(sizeof(struct cap_hdr), 1);
6582 hdr->next = curproxy->rsp_cap;
6583 hdr->name = strdup(args[3]);
6584 hdr->namelen = strlen(args[3]);
6585 hdr->len = atol(args[5]);
6586 hdr->index = curproxy->nb_rsp_cap++;
6587 curproxy->rsp_cap = hdr;
6588 curproxy->to_log |= LW_RSPHDR;
6589 }
6590 else {
6591 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006592 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006593 return -1;
6594 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006595 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006596 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006597 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006598 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006599 return 0;
6600 }
6601 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006602 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6603 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006604 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006605 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006606 curproxy->contimeout = atol(args[1]);
6607 }
6608 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006609 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006610 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6611 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006612 return 0;
6613 }
6614 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006615 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6616 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006617 return -1;
6618 }
6619 curproxy->clitimeout = atol(args[1]);
6620 }
6621 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006622 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006623 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006624 return 0;
6625 }
6626 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006627 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6628 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006629 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006630 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006631 curproxy->srvtimeout = atol(args[1]);
6632 }
6633 else if (!strcmp(args[0], "retries")) { /* connection retries */
6634 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006635 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6636 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006637 return -1;
6638 }
6639 curproxy->conn_retries = atol(args[1]);
6640 }
6641 else if (!strcmp(args[0], "option")) {
6642 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006643 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006644 return -1;
6645 }
6646 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006647 /* enable reconnections to dispatch */
6648 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006649#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006650 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006651 /* enable transparent proxy connections */
6652 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006653#endif
6654 else if (!strcmp(args[1], "keepalive"))
6655 /* enable keep-alive */
6656 curproxy->options |= PR_O_KEEPALIVE;
6657 else if (!strcmp(args[1], "forwardfor"))
6658 /* insert x-forwarded-for field */
6659 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006660 else if (!strcmp(args[1], "logasap"))
6661 /* log as soon as possible, without waiting for the session to complete */
6662 curproxy->options |= PR_O_LOGASAP;
6663 else if (!strcmp(args[1], "httpclose"))
6664 /* force connection: close in both directions in HTTP mode */
6665 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01006666 else if (!strcmp(args[1], "forceclose"))
6667 /* force connection: close in both directions in HTTP mode and enforce end of session */
6668 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006669 else if (!strcmp(args[1], "checkcache"))
6670 /* require examination of cacheability of the 'set-cookie' field */
6671 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006672 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006673 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006674 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006675 else if (!strcmp(args[1], "tcplog"))
6676 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006677 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006678 else if (!strcmp(args[1], "dontlognull")) {
6679 /* don't log empty requests */
6680 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006681 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006682 else if (!strcmp(args[1], "tcpka")) {
6683 /* enable TCP keep-alives on client and server sessions */
6684 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6685 }
6686 else if (!strcmp(args[1], "clitcpka")) {
6687 /* enable TCP keep-alives on client sessions */
6688 curproxy->options |= PR_O_TCP_CLI_KA;
6689 }
6690 else if (!strcmp(args[1], "srvtcpka")) {
6691 /* enable TCP keep-alives on server sessions */
6692 curproxy->options |= PR_O_TCP_SRV_KA;
6693 }
Willy TARREAU3481c462006-03-01 22:37:57 +01006694 else if (!strcmp(args[1], "allbackups")) {
6695 /* Use all backup servers simultaneously */
6696 curproxy->options |= PR_O_USE_ALL_BK;
6697 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006698 else if (!strcmp(args[1], "httpchk")) {
6699 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006700 if (curproxy->check_req != NULL) {
6701 free(curproxy->check_req);
6702 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006703 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006704 if (!*args[2]) { /* no argument */
6705 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6706 curproxy->check_len = strlen(DEF_CHECK_REQ);
6707 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006708 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6709 curproxy->check_req = (char *)malloc(reqlen);
6710 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6711 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006712 } else { /* more arguments : METHOD URI [HTTP_VER] */
6713 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6714 if (*args[4])
6715 reqlen += strlen(args[4]);
6716 else
6717 reqlen += strlen("HTTP/1.0");
6718
6719 curproxy->check_req = (char *)malloc(reqlen);
6720 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6721 "%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 +01006722 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006723 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006724 else if (!strcmp(args[1], "persist")) {
6725 /* persist on using the server specified by the cookie, even when it's down */
6726 curproxy->options |= PR_O_PERSIST;
6727 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006728 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006729 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006730 return -1;
6731 }
6732 return 0;
6733 }
6734 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6735 /* enable reconnections to dispatch */
6736 curproxy->options |= PR_O_REDISP;
6737 }
willy tarreaua1598082005-12-17 13:08:06 +01006738#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006739 else if (!strcmp(args[0], "transparent")) {
6740 /* enable transparent proxy connections */
6741 curproxy->options |= PR_O_TRANSP;
6742 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006743#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006744 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6745 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006746 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006747 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006748 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006749 curproxy->maxconn = atol(args[1]);
6750 }
6751 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6752 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006753 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006754 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006755 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006756 curproxy->grace = atol(args[1]);
6757 }
6758 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006759 if (curproxy == &defproxy) {
6760 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6761 return -1;
6762 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006763 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006764 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006765 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006766 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006767 curproxy->dispatch_addr = *str2sa(args[1]);
6768 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006769 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006770 if (*(args[1])) {
6771 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006772 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006773 }
6774 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006775 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006776 return -1;
6777 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006778 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006779 else /* if no option is set, use round-robin by default */
6780 curproxy->options |= PR_O_BALANCE_RR;
6781 }
6782 else if (!strcmp(args[0], "server")) { /* server address */
6783 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006784 char *rport;
6785 char *raddr;
6786 short realport;
6787 int do_check;
6788
6789 if (curproxy == &defproxy) {
6790 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6791 return -1;
6792 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006793
willy tarreaua41a8b42005-12-17 14:02:24 +01006794 if (!*args[2]) {
6795 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006796 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006797 return -1;
6798 }
6799 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6800 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6801 return -1;
6802 }
willy tarreau0174f312005-12-18 01:02:42 +01006803
6804 if (curproxy->srv == NULL)
6805 curproxy->srv = newsrv;
6806 else
6807 curproxy->cursrv->next = newsrv;
6808 curproxy->cursrv = newsrv;
6809
6810 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006811 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006812
6813 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006814 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006815 newsrv->id = strdup(args[1]);
6816
6817 /* several ways to check the port component :
6818 * - IP => port=+0, relative
6819 * - IP: => port=+0, relative
6820 * - IP:N => port=N, absolute
6821 * - IP:+N => port=+N, relative
6822 * - IP:-N => port=-N, relative
6823 */
6824 raddr = strdup(args[2]);
6825 rport = strchr(raddr, ':');
6826 if (rport) {
6827 *rport++ = 0;
6828 realport = atol(rport);
6829 if (!isdigit((int)*rport))
6830 newsrv->state |= SRV_MAPPORTS;
6831 } else {
6832 realport = 0;
6833 newsrv->state |= SRV_MAPPORTS;
6834 }
6835
6836 newsrv->addr = *str2sa(raddr);
6837 newsrv->addr.sin_port = htons(realport);
6838 free(raddr);
6839
willy tarreau9fe663a2005-12-17 13:02:59 +01006840 newsrv->curfd = -1; /* no health-check in progress */
6841 newsrv->inter = DEF_CHKINTR;
6842 newsrv->rise = DEF_RISETIME;
6843 newsrv->fall = DEF_FALLTIME;
6844 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
6845 cur_arg = 3;
6846 while (*args[cur_arg]) {
6847 if (!strcmp(args[cur_arg], "cookie")) {
6848 newsrv->cookie = strdup(args[cur_arg + 1]);
6849 newsrv->cklen = strlen(args[cur_arg + 1]);
6850 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006851 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006852 else if (!strcmp(args[cur_arg], "rise")) {
6853 newsrv->rise = atol(args[cur_arg + 1]);
6854 newsrv->health = newsrv->rise;
6855 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006856 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006857 else if (!strcmp(args[cur_arg], "fall")) {
6858 newsrv->fall = atol(args[cur_arg + 1]);
6859 cur_arg += 2;
6860 }
6861 else if (!strcmp(args[cur_arg], "inter")) {
6862 newsrv->inter = atol(args[cur_arg + 1]);
6863 cur_arg += 2;
6864 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006865 else if (!strcmp(args[cur_arg], "port")) {
6866 newsrv->check_port = atol(args[cur_arg + 1]);
6867 cur_arg += 2;
6868 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006869 else if (!strcmp(args[cur_arg], "backup")) {
6870 newsrv->state |= SRV_BACKUP;
6871 cur_arg ++;
6872 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006873 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01006874 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006875 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006876 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006877 }
willy tarreau0174f312005-12-18 01:02:42 +01006878 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
6879 if (!*args[cur_arg + 1]) {
6880 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
6881 file, linenum, "source");
6882 return -1;
6883 }
6884 newsrv->state |= SRV_BIND_SRC;
6885 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
6886 cur_arg += 2;
6887 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006888 else {
willy tarreau0174f312005-12-18 01:02:42 +01006889 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 +01006890 file, linenum, newsrv->id);
6891 return -1;
6892 }
6893 }
6894
6895 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006896 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
6897 newsrv->check_port = realport; /* by default */
6898 if (!newsrv->check_port) {
6899 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 +01006900 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006901 return -1;
6902 }
Willy TARREAU3759f982006-03-01 22:44:17 +01006903 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006904 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006905
willy tarreau9fe663a2005-12-17 13:02:59 +01006906 curproxy->nbservers++;
6907 }
6908 else if (!strcmp(args[0], "log")) { /* syslog server address */
6909 struct sockaddr_in *sa;
6910 int facility;
6911
6912 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
6913 curproxy->logfac1 = global.logfac1;
6914 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006915 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006916 curproxy->logfac2 = global.logfac2;
6917 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01006918 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01006919 }
6920 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01006921 int level;
6922
willy tarreau0f7af912005-12-17 12:21:26 +01006923 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6924 if (!strcmp(log_facilities[facility], args[2]))
6925 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01006926
willy tarreau0f7af912005-12-17 12:21:26 +01006927 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006928 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01006929 exit(1);
6930 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006931
willy tarreau8337c6b2005-12-17 13:41:01 +01006932 level = 7; /* max syslog level = debug */
6933 if (*(args[3])) {
6934 while (level >= 0 && strcmp(log_levels[level], args[3]))
6935 level--;
6936 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006937 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006938 exit(1);
6939 }
6940 }
6941
willy tarreau0f7af912005-12-17 12:21:26 +01006942 sa = str2sa(args[1]);
6943 if (!sa->sin_port)
6944 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01006945
willy tarreau0f7af912005-12-17 12:21:26 +01006946 if (curproxy->logfac1 == -1) {
6947 curproxy->logsrv1 = *sa;
6948 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006949 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006950 }
6951 else if (curproxy->logfac2 == -1) {
6952 curproxy->logsrv2 = *sa;
6953 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006954 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006955 }
6956 else {
6957 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006958 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006959 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006960 }
6961 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006962 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006963 file, linenum);
6964 return -1;
6965 }
6966 }
willy tarreaua1598082005-12-17 13:08:06 +01006967 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01006968 if (!*args[1]) {
6969 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006970 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01006971 return -1;
6972 }
6973
6974 curproxy->source_addr = *str2sa(args[1]);
6975 curproxy->options |= PR_O_BIND_SRC;
6976 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006977 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
6978 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006979 if (curproxy == &defproxy) {
6980 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6981 return -1;
6982 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006983
6984 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006985 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6986 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006987 return -1;
6988 }
6989
6990 preg = calloc(1, sizeof(regex_t));
6991 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006992 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006993 return -1;
6994 }
6995
willy tarreauc1f47532005-12-18 01:08:26 +01006996 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6997 if (err) {
6998 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6999 file, linenum, *err);
7000 return -1;
7001 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007002 }
7003 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7004 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007005 if (curproxy == &defproxy) {
7006 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7007 return -1;
7008 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007009
7010 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007011 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007012 return -1;
7013 }
7014
7015 preg = calloc(1, sizeof(regex_t));
7016 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007017 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007018 return -1;
7019 }
7020
7021 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7022 }
7023 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7024 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007025 if (curproxy == &defproxy) {
7026 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7027 return -1;
7028 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007029
7030 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007031 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007032 return -1;
7033 }
7034
7035 preg = calloc(1, sizeof(regex_t));
7036 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007037 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007038 return -1;
7039 }
7040
7041 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7042 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007043 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7044 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007045 if (curproxy == &defproxy) {
7046 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7047 return -1;
7048 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007049
7050 if (*(args[1]) == 0) {
7051 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7052 return -1;
7053 }
7054
7055 preg = calloc(1, sizeof(regex_t));
7056 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7057 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7058 return -1;
7059 }
7060
7061 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7062 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007063 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7064 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007065 if (curproxy == &defproxy) {
7066 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7067 return -1;
7068 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007069
7070 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007071 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007072 return -1;
7073 }
7074
7075 preg = calloc(1, sizeof(regex_t));
7076 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007077 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007078 return -1;
7079 }
7080
7081 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7082 }
7083 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7084 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007085 if (curproxy == &defproxy) {
7086 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7087 return -1;
7088 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007089
7090 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007091 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7092 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007093 return -1;
7094 }
7095
7096 preg = calloc(1, sizeof(regex_t));
7097 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007098 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007099 return -1;
7100 }
7101
willy tarreauc1f47532005-12-18 01:08:26 +01007102 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7103 if (err) {
7104 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7105 file, linenum, *err);
7106 return -1;
7107 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007108 }
7109 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7110 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007111 if (curproxy == &defproxy) {
7112 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7113 return -1;
7114 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007115
7116 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007117 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007118 return -1;
7119 }
7120
7121 preg = calloc(1, sizeof(regex_t));
7122 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007123 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007124 return -1;
7125 }
7126
7127 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7128 }
7129 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7130 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007131 if (curproxy == &defproxy) {
7132 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7133 return -1;
7134 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007135
7136 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007137 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007138 return -1;
7139 }
7140
7141 preg = calloc(1, sizeof(regex_t));
7142 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007143 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007144 return -1;
7145 }
7146
7147 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7148 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007149 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7150 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007151 if (curproxy == &defproxy) {
7152 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7153 return -1;
7154 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007155
7156 if (*(args[1]) == 0) {
7157 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7158 return -1;
7159 }
7160
7161 preg = calloc(1, sizeof(regex_t));
7162 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7163 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7164 return -1;
7165 }
7166
7167 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7168 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007169 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7170 regex_t *preg;
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 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007175
7176 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007177 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007178 return -1;
7179 }
7180
7181 preg = calloc(1, sizeof(regex_t));
7182 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007183 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007184 return -1;
7185 }
7186
7187 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7188 }
7189 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007190 if (curproxy == &defproxy) {
7191 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7192 return -1;
7193 }
7194
willy tarreau9fe663a2005-12-17 13:02:59 +01007195 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007196 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007197 return 0;
7198 }
7199
7200 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007201 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007202 return -1;
7203 }
7204
willy tarreau4302f492005-12-18 01:00:37 +01007205 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7206 }
7207 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7208 regex_t *preg;
7209
7210 if (*(args[1]) == 0 || *(args[2]) == 0) {
7211 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7212 file, linenum, args[0]);
7213 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007214 }
willy tarreau4302f492005-12-18 01:00:37 +01007215
7216 preg = calloc(1, sizeof(regex_t));
7217 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7218 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7219 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007220 }
willy tarreau4302f492005-12-18 01:00:37 +01007221
willy tarreauc1f47532005-12-18 01:08:26 +01007222 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7223 if (err) {
7224 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7225 file, linenum, *err);
7226 return -1;
7227 }
willy tarreau4302f492005-12-18 01:00:37 +01007228 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007229 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7230 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007231 if (curproxy == &defproxy) {
7232 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7233 return -1;
7234 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007235
7236 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007237 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007238 return -1;
7239 }
willy tarreaue39cd132005-12-17 13:00:18 +01007240
willy tarreau9fe663a2005-12-17 13:02:59 +01007241 preg = calloc(1, sizeof(regex_t));
7242 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007243 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007244 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007245 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007246
willy tarreauc1f47532005-12-18 01:08:26 +01007247 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7248 if (err) {
7249 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7250 file, linenum, *err);
7251 return -1;
7252 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007253 }
willy tarreau982249e2005-12-18 00:57:06 +01007254 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7255 regex_t *preg;
7256 if (curproxy == &defproxy) {
7257 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7258 return -1;
7259 }
7260
7261 if (*(args[1]) == 0) {
7262 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7263 return -1;
7264 }
7265
7266 preg = calloc(1, sizeof(regex_t));
7267 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7268 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7269 return -1;
7270 }
7271
willy tarreauc1f47532005-12-18 01:08:26 +01007272 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7273 if (err) {
7274 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7275 file, linenum, *err);
7276 return -1;
7277 }
willy tarreau982249e2005-12-18 00:57:06 +01007278 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007279 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007280 regex_t *preg;
7281 if (curproxy == &defproxy) {
7282 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7283 return -1;
7284 }
willy tarreaue39cd132005-12-17 13:00:18 +01007285
willy tarreaua41a8b42005-12-17 14:02:24 +01007286 if (*(args[1]) == 0 || *(args[2]) == 0) {
7287 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7288 file, linenum, args[0]);
7289 return -1;
7290 }
willy tarreaue39cd132005-12-17 13:00:18 +01007291
willy tarreaua41a8b42005-12-17 14:02:24 +01007292 preg = calloc(1, sizeof(regex_t));
7293 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7294 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7295 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007296 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007297
willy tarreauc1f47532005-12-18 01:08:26 +01007298 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7299 if (err) {
7300 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7301 file, linenum, *err);
7302 return -1;
7303 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007304 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007305 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7306 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007307 if (curproxy == &defproxy) {
7308 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7309 return -1;
7310 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007311
7312 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007313 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007314 return -1;
7315 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007316
willy tarreau9fe663a2005-12-17 13:02:59 +01007317 preg = calloc(1, sizeof(regex_t));
7318 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007319 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007320 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007321 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007322
willy tarreauc1f47532005-12-18 01:08:26 +01007323 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7324 if (err) {
7325 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7326 file, linenum, *err);
7327 return -1;
7328 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007329 }
willy tarreau982249e2005-12-18 00:57:06 +01007330 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7331 regex_t *preg;
7332 if (curproxy == &defproxy) {
7333 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7334 return -1;
7335 }
7336
7337 if (*(args[1]) == 0) {
7338 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7339 return -1;
7340 }
7341
7342 preg = calloc(1, sizeof(regex_t));
7343 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7344 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7345 return -1;
7346 }
7347
willy tarreauc1f47532005-12-18 01:08:26 +01007348 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7349 if (err) {
7350 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7351 file, linenum, *err);
7352 return -1;
7353 }
willy tarreau982249e2005-12-18 00:57:06 +01007354 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007355 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007356 if (curproxy == &defproxy) {
7357 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7358 return -1;
7359 }
7360
willy tarreau9fe663a2005-12-17 13:02:59 +01007361 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007362 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007363 return 0;
7364 }
7365
7366 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007367 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007368 return -1;
7369 }
7370
7371 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7372 }
willy tarreauc1f47532005-12-18 01:08:26 +01007373 else if (!strcmp(args[0], "errorloc") ||
7374 !strcmp(args[0], "errorloc302") ||
7375 !strcmp(args[0], "errorloc303")) { /* error location */
7376 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007377 char *err;
7378
willy tarreaueedaa9f2005-12-17 14:08:03 +01007379 // if (curproxy == &defproxy) {
7380 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7381 // return -1;
7382 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007383
willy tarreau8337c6b2005-12-17 13:41:01 +01007384 if (*(args[2]) == 0) {
7385 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7386 return -1;
7387 }
7388
7389 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007390 if (!strcmp(args[0], "errorloc303")) {
7391 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7392 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7393 } else {
7394 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7395 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7396 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007397
7398 if (errnum == 400) {
7399 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007400 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007401 free(curproxy->errmsg.msg400);
7402 }
7403 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007404 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007405 }
7406 else if (errnum == 403) {
7407 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007408 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007409 free(curproxy->errmsg.msg403);
7410 }
7411 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007412 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007413 }
7414 else if (errnum == 408) {
7415 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007416 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007417 free(curproxy->errmsg.msg408);
7418 }
7419 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007420 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007421 }
7422 else if (errnum == 500) {
7423 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007424 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007425 free(curproxy->errmsg.msg500);
7426 }
7427 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007428 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007429 }
7430 else if (errnum == 502) {
7431 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007432 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007433 free(curproxy->errmsg.msg502);
7434 }
7435 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007436 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007437 }
7438 else if (errnum == 503) {
7439 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007440 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007441 free(curproxy->errmsg.msg503);
7442 }
7443 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007444 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007445 }
7446 else if (errnum == 504) {
7447 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007448 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007449 free(curproxy->errmsg.msg504);
7450 }
7451 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007452 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007453 }
7454 else {
7455 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7456 free(err);
7457 }
7458 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007459 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007460 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007461 return -1;
7462 }
7463 return 0;
7464}
willy tarreaue39cd132005-12-17 13:00:18 +01007465
willy tarreau5cbea6f2005-12-17 12:48:26 +01007466
willy tarreau9fe663a2005-12-17 13:02:59 +01007467/*
7468 * This function reads and parses the configuration file given in the argument.
7469 * returns 0 if OK, -1 if error.
7470 */
7471int readcfgfile(char *file) {
7472 char thisline[256];
7473 char *line;
7474 FILE *f;
7475 int linenum = 0;
7476 char *end;
7477 char *args[MAX_LINE_ARGS];
7478 int arg;
7479 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007480 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007481 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007482
willy tarreau9fe663a2005-12-17 13:02:59 +01007483 struct proxy *curproxy = NULL;
7484 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007485
willy tarreau9fe663a2005-12-17 13:02:59 +01007486 if ((f=fopen(file,"r")) == NULL)
7487 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007488
willy tarreaueedaa9f2005-12-17 14:08:03 +01007489 init_default_instance();
7490
willy tarreau9fe663a2005-12-17 13:02:59 +01007491 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7492 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007493
willy tarreau9fe663a2005-12-17 13:02:59 +01007494 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007495
willy tarreau9fe663a2005-12-17 13:02:59 +01007496 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007497 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007498 line++;
7499
7500 arg = 0;
7501 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007502
willy tarreau9fe663a2005-12-17 13:02:59 +01007503 while (*line && arg < MAX_LINE_ARGS) {
7504 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7505 * C equivalent value. Other combinations left unchanged (eg: \1).
7506 */
7507 if (*line == '\\') {
7508 int skip = 0;
7509 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7510 *line = line[1];
7511 skip = 1;
7512 }
7513 else if (line[1] == 'r') {
7514 *line = '\r';
7515 skip = 1;
7516 }
7517 else if (line[1] == 'n') {
7518 *line = '\n';
7519 skip = 1;
7520 }
7521 else if (line[1] == 't') {
7522 *line = '\t';
7523 skip = 1;
7524 }
willy tarreauc1f47532005-12-18 01:08:26 +01007525 else if (line[1] == 'x') {
7526 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7527 unsigned char hex1, hex2;
7528 hex1 = toupper(line[2]) - '0';
7529 hex2 = toupper(line[3]) - '0';
7530 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7531 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7532 *line = (hex1<<4) + hex2;
7533 skip = 3;
7534 }
7535 else {
7536 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7537 return -1;
7538 }
7539 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007540 if (skip) {
7541 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7542 end -= skip;
7543 }
7544 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007545 }
willy tarreaua1598082005-12-17 13:08:06 +01007546 else if (*line == '#' || *line == '\n' || *line == '\r') {
7547 /* end of string, end of loop */
7548 *line = 0;
7549 break;
7550 }
willy tarreauc29948c2005-12-17 13:10:27 +01007551 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007552 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007553 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007554 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007555 line++;
7556 args[++arg] = line;
7557 }
7558 else {
7559 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007560 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007561 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007562
willy tarreau9fe663a2005-12-17 13:02:59 +01007563 /* empty line */
7564 if (!**args)
7565 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007566
willy tarreau9fe663a2005-12-17 13:02:59 +01007567 /* zero out remaining args */
7568 while (++arg < MAX_LINE_ARGS) {
7569 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007570 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007571
willy tarreaua41a8b42005-12-17 14:02:24 +01007572 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007573 confsect = CFG_LISTEN;
7574 else if (!strcmp(args[0], "global")) /* global config */
7575 confsect = CFG_GLOBAL;
7576 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007577
willy tarreau9fe663a2005-12-17 13:02:59 +01007578 switch (confsect) {
7579 case CFG_LISTEN:
7580 if (cfg_parse_listen(file, linenum, args) < 0)
7581 return -1;
7582 break;
7583 case CFG_GLOBAL:
7584 if (cfg_parse_global(file, linenum, args) < 0)
7585 return -1;
7586 break;
7587 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007588 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007589 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007590 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007591
7592
willy tarreau0f7af912005-12-17 12:21:26 +01007593 }
7594 fclose(f);
7595
7596 /*
7597 * Now, check for the integrity of all that we have collected.
7598 */
7599
Willy TARREAU3759f982006-03-01 22:44:17 +01007600 /* will be needed further to delay some tasks */
7601 tv_now(&now);
7602
willy tarreau0f7af912005-12-17 12:21:26 +01007603 if ((curproxy = proxy) == NULL) {
7604 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7605 file);
7606 return -1;
7607 }
7608
7609 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007610 curproxy->cursrv = NULL;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007611 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007612 curproxy = curproxy->next;
7613 continue;
7614 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007615
7616 if (curproxy->listen == NULL) {
7617 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);
7618 cfgerr++;
7619 }
7620 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007621 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007622 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007623 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7624 file, curproxy->id);
7625 cfgerr++;
7626 }
7627 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7628 if (curproxy->options & PR_O_TRANSP) {
7629 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7630 file, curproxy->id);
7631 cfgerr++;
7632 }
7633 else if (curproxy->srv == NULL) {
7634 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7635 file, curproxy->id);
7636 cfgerr++;
7637 }
willy tarreaua1598082005-12-17 13:08:06 +01007638 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007639 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7640 file, curproxy->id);
7641 }
7642 }
7643 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007644 if (curproxy->cookie_name != NULL) {
7645 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7646 file, curproxy->id);
7647 }
7648 if ((newsrv = curproxy->srv) != NULL) {
7649 Warning("parsing %s : servers will be ignored for listener %s.\n",
7650 file, curproxy->id);
7651 }
willy tarreaue39cd132005-12-17 13:00:18 +01007652 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007653 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7654 file, curproxy->id);
7655 }
willy tarreaue39cd132005-12-17 13:00:18 +01007656 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007657 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7658 file, curproxy->id);
7659 }
7660 }
7661 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7662 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7663 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7664 file, curproxy->id);
7665 cfgerr++;
7666 }
7667 else {
7668 while (newsrv != NULL) {
7669 /* nothing to check for now */
7670 newsrv = newsrv->next;
7671 }
7672 }
7673 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007674
7675 if (curproxy->options & PR_O_LOGASAP)
7676 curproxy->to_log &= ~LW_BYTES;
7677
willy tarreau8337c6b2005-12-17 13:41:01 +01007678 if (curproxy->errmsg.msg400 == NULL) {
7679 curproxy->errmsg.msg400 = (char *)HTTP_400;
7680 curproxy->errmsg.len400 = strlen(HTTP_400);
7681 }
7682 if (curproxy->errmsg.msg403 == NULL) {
7683 curproxy->errmsg.msg403 = (char *)HTTP_403;
7684 curproxy->errmsg.len403 = strlen(HTTP_403);
7685 }
7686 if (curproxy->errmsg.msg408 == NULL) {
7687 curproxy->errmsg.msg408 = (char *)HTTP_408;
7688 curproxy->errmsg.len408 = strlen(HTTP_408);
7689 }
7690 if (curproxy->errmsg.msg500 == NULL) {
7691 curproxy->errmsg.msg500 = (char *)HTTP_500;
7692 curproxy->errmsg.len500 = strlen(HTTP_500);
7693 }
7694 if (curproxy->errmsg.msg502 == NULL) {
7695 curproxy->errmsg.msg502 = (char *)HTTP_502;
7696 curproxy->errmsg.len502 = strlen(HTTP_502);
7697 }
7698 if (curproxy->errmsg.msg503 == NULL) {
7699 curproxy->errmsg.msg503 = (char *)HTTP_503;
7700 curproxy->errmsg.len503 = strlen(HTTP_503);
7701 }
7702 if (curproxy->errmsg.msg504 == NULL) {
7703 curproxy->errmsg.msg504 = (char *)HTTP_504;
7704 curproxy->errmsg.len504 = strlen(HTTP_504);
7705 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007706
7707 /* now we'll start this proxy's health checks if any */
7708 /* 1- count the checkers to run simultaneously */
7709 nbchk = 0;
7710 mininter = 0;
7711 newsrv = curproxy->srv;
7712 while (newsrv != NULL) {
7713 if (newsrv->state & SRV_CHECKED) {
7714 if (!mininter || mininter > newsrv->inter)
7715 mininter = newsrv->inter;
7716 nbchk++;
7717 }
7718 newsrv = newsrv->next;
7719 }
7720
7721 /* 2- start them as far as possible from each others while respecting
7722 * their own intervals. For this, we will start them after their own
7723 * interval added to the min interval divided by the number of servers,
7724 * weighted by the server's position in the list.
7725 */
7726 if (nbchk > 0) {
7727 struct task *t;
7728 int srvpos;
7729
7730 newsrv = curproxy->srv;
7731 srvpos = 0;
7732 while (newsrv != NULL) {
7733 /* should this server be checked ? */
7734 if (newsrv->state & SRV_CHECKED) {
7735 if ((t = pool_alloc(task)) == NULL) {
7736 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7737 return -1;
7738 }
7739
7740 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
7741 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
7742 t->state = TASK_IDLE;
7743 t->process = process_chk;
7744 t->context = newsrv;
7745
7746 /* check this every ms */
7747 tv_delayfrom(&t->expire, &now,
7748 newsrv->inter + mininter * srvpos / nbchk);
7749 task_queue(t);
7750 //task_wakeup(&rq, t);
7751 srvpos++;
7752 }
7753 newsrv = newsrv->next;
7754 }
7755 }
7756
willy tarreau0f7af912005-12-17 12:21:26 +01007757 curproxy = curproxy->next;
7758 }
7759 if (cfgerr > 0) {
7760 Alert("Errors found in configuration file, aborting.\n");
7761 return -1;
7762 }
7763 else
7764 return 0;
7765}
7766
7767
7768/*
7769 * This function initializes all the necessary variables. It only returns
7770 * if everything is OK. If something fails, it exits.
7771 */
7772void init(int argc, char **argv) {
7773 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007774 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007775 char *old_argv = *argv;
7776 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007777 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007778
7779 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007780 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007781 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007782 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007783 exit(1);
7784 }
7785
Willy TARREAUa9e75f62006-03-01 22:27:48 +01007786 /* initialize the libc's localtime structures once for all so that we
7787 * won't be missing memory if we want to send alerts under OOM conditions.
7788 */
7789 tv_now(&now);
7790 localtime(&now.tv_sec);
7791
willy tarreau4302f492005-12-18 01:00:37 +01007792 /* initialize the log header encoding map : '{|}"#' should be encoded with
7793 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7794 * URL encoding only requires '"', '#' to be encoded as well as non-
7795 * printable characters above.
7796 */
7797 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7798 memset(url_encode_map, 0, sizeof(url_encode_map));
7799 for (i = 0; i < 32; i++) {
7800 FD_SET(i, hdr_encode_map);
7801 FD_SET(i, url_encode_map);
7802 }
7803 for (i = 127; i < 256; i++) {
7804 FD_SET(i, hdr_encode_map);
7805 FD_SET(i, url_encode_map);
7806 }
7807
7808 tmp = "\"#{|}";
7809 while (*tmp) {
7810 FD_SET(*tmp, hdr_encode_map);
7811 tmp++;
7812 }
7813
7814 tmp = "\"#";
7815 while (*tmp) {
7816 FD_SET(*tmp, url_encode_map);
7817 tmp++;
7818 }
7819
willy tarreau64a3cc32005-12-18 01:13:11 +01007820 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
7821#if defined(ENABLE_POLL)
7822 cfg_polling_mechanism |= POLL_USE_POLL;
7823#endif
7824#if defined(ENABLE_EPOLL)
7825 cfg_polling_mechanism |= POLL_USE_EPOLL;
7826#endif
7827
willy tarreau0f7af912005-12-17 12:21:26 +01007828 pid = getpid();
7829 progname = *argv;
7830 while ((tmp = strchr(progname, '/')) != NULL)
7831 progname = tmp + 1;
7832
7833 argc--; argv++;
7834 while (argc > 0) {
7835 char *flag;
7836
7837 if (**argv == '-') {
7838 flag = *argv+1;
7839
7840 /* 1 arg */
7841 if (*flag == 'v') {
7842 display_version();
7843 exit(0);
7844 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007845#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007846 else if (*flag == 'd' && flag[1] == 'e')
7847 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007848#endif
7849#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007850 else if (*flag == 'd' && flag[1] == 'p')
7851 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007852#endif
willy tarreau982249e2005-12-18 00:57:06 +01007853 else if (*flag == 'V')
7854 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01007855 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01007856 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01007857 else if (*flag == 'c')
7858 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01007859 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01007860 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007861 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01007862 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01007863#if STATTIME > 0
7864 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01007865 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01007866 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01007867 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01007868#endif
7869 else { /* >=2 args */
7870 argv++; argc--;
7871 if (argc == 0)
7872 usage(old_argv);
7873
7874 switch (*flag) {
7875 case 'n' : cfg_maxconn = atol(*argv); break;
7876 case 'N' : cfg_maxpconn = atol(*argv); break;
7877 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007878 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01007879 default: usage(old_argv);
7880 }
7881 }
7882 }
7883 else
7884 usage(old_argv);
7885 argv++; argc--;
7886 }
7887
willy tarreaud0fb4652005-12-18 01:32:04 +01007888 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
7889 (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01007890
willy tarreau0f7af912005-12-17 12:21:26 +01007891 if (!cfg_cfgfile)
7892 usage(old_argv);
7893
7894 gethostname(hostname, MAX_HOSTNAME_LEN);
7895
willy tarreau12350152005-12-18 01:03:27 +01007896 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007897 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01007898 if (readcfgfile(cfg_cfgfile) < 0) {
7899 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
7900 exit(1);
7901 }
willy tarreau12350152005-12-18 01:03:27 +01007902 if (have_appsession)
7903 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01007904
willy tarreau982249e2005-12-18 00:57:06 +01007905 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01007906 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
7907 exit(0);
7908 }
7909
willy tarreau9fe663a2005-12-17 13:02:59 +01007910 if (cfg_maxconn > 0)
7911 global.maxconn = cfg_maxconn;
7912
willy tarreaufe2c5c12005-12-17 14:14:34 +01007913 if (cfg_pidfile) {
7914 if (global.pidfile)
7915 free(global.pidfile);
7916 global.pidfile = strdup(cfg_pidfile);
7917 }
7918
willy tarreau9fe663a2005-12-17 13:02:59 +01007919 if (global.maxconn == 0)
7920 global.maxconn = DEFAULT_MAXCONN;
7921
Willy TARREAU203b0b62006-03-12 18:00:28 +01007922 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01007923
7924 if (arg_mode & MODE_DEBUG) {
7925 /* command line debug mode inhibits configuration mode */
7926 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7927 }
willy tarreau982249e2005-12-18 00:57:06 +01007928 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
7929 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01007930
7931 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
7932 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
7933 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7934 }
7935
7936 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
7937 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
7938 global.nbproc = 1;
7939 }
7940
7941 if (global.nbproc < 1)
7942 global.nbproc = 1;
7943
willy tarreau0f7af912005-12-17 12:21:26 +01007944 StaticReadEvent = (fd_set *)calloc(1,
7945 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007946 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007947 StaticWriteEvent = (fd_set *)calloc(1,
7948 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007949 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007950
7951 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01007952 sizeof(struct fdtab) * (global.maxsock));
7953 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01007954 fdtab[i].state = FD_STCLOSE;
7955 }
7956}
7957
7958/*
7959 * this function starts all the proxies. It returns 0 if OK, -1 if not.
7960 */
7961int start_proxies() {
7962 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007963 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01007964 int fd;
7965
7966 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007967 if (curproxy->state == PR_STSTOPPED)
willy tarreau0f7af912005-12-17 12:21:26 +01007968 continue;
7969
willy tarreaua41a8b42005-12-17 14:02:24 +01007970 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
7971 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01007972 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007973 Alert("cannot create listening socket for proxy %s. Aborting.\n",
7974 curproxy->id);
7975 return -1;
7976 }
willy tarreau0f7af912005-12-17 12:21:26 +01007977
willy tarreaua41a8b42005-12-17 14:02:24 +01007978 if (fd >= global.maxsock) {
7979 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
7980 curproxy->id);
7981 close(fd);
7982 return -1;
7983 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007984
willy tarreaua41a8b42005-12-17 14:02:24 +01007985 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
7986 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
7987 (char *) &one, sizeof(one)) == -1)) {
7988 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
7989 curproxy->id);
7990 close(fd);
7991 return -1;
7992 }
willy tarreau0f7af912005-12-17 12:21:26 +01007993
willy tarreaua41a8b42005-12-17 14:02:24 +01007994 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
7995 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
7996 curproxy->id);
7997 }
willy tarreau0f7af912005-12-17 12:21:26 +01007998
willy tarreaua41a8b42005-12-17 14:02:24 +01007999 if (bind(fd,
8000 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008001 listener->addr.ss_family == AF_INET6 ?
8002 sizeof(struct sockaddr_in6) :
8003 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008004 Alert("cannot bind socket for proxy %s. Aborting.\n",
8005 curproxy->id);
8006 close(fd);
8007 return -1;
8008 }
willy tarreau0f7af912005-12-17 12:21:26 +01008009
willy tarreaua41a8b42005-12-17 14:02:24 +01008010 if (listen(fd, curproxy->maxconn) == -1) {
8011 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8012 curproxy->id);
8013 close(fd);
8014 return -1;
8015 }
willy tarreau0f7af912005-12-17 12:21:26 +01008016
willy tarreaua41a8b42005-12-17 14:02:24 +01008017 /* the function for the accept() event */
8018 fdtab[fd].read = &event_accept;
8019 fdtab[fd].write = NULL; /* never called */
8020 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
8021 curproxy->state = PR_STRUN;
8022 fdtab[fd].state = FD_STLISTEN;
8023 FD_SET(fd, StaticReadEvent);
8024 fd_insert(fd);
8025 listeners++;
8026 }
willy tarreaua1598082005-12-17 13:08:06 +01008027 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01008028 }
8029 return 0;
8030}
8031
willy tarreaub952e1d2005-12-18 01:31:20 +01008032int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008033
8034 appsess *temp1,*temp2;
8035 temp1 = (appsess *)key1;
8036 temp2 = (appsess *)key2;
8037
8038 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8039 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8040
8041 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8042}/* end match_str */
8043
willy tarreaub952e1d2005-12-18 01:31:20 +01008044void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008045 appsess *temp1;
8046
8047 //printf("destroy called\n");
8048 temp1 = (appsess *)data;
8049
8050 if (temp1->sessid)
8051 pool_free_to(apools.sessid, temp1->sessid);
8052
8053 if (temp1->serverid)
8054 pool_free_to(apools.serverid, temp1->serverid);
8055
8056 pool_free(appsess, temp1);
8057} /* end destroy */
8058
8059void appsession_cleanup( void )
8060{
8061 struct proxy *p = proxy;
8062
8063 while(p) {
8064 chtbl_destroy(&(p->htbl_proxy));
8065 p = p->next;
8066 }
8067}/* end appsession_cleanup() */
8068
8069void pool_destroy(void **pool)
8070{
8071 void *temp, *next;
8072 next = pool;
8073 while (next) {
8074 temp = next;
8075 next = *(void **)temp;
8076 free(temp);
8077 }
8078}/* end pool_destroy() */
8079
willy tarreaub952e1d2005-12-18 01:31:20 +01008080void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008081 struct proxy *p = proxy;
8082 struct cap_hdr *h,*h_next;
8083 struct server *s,*s_next;
8084 struct listener *l,*l_next;
8085
8086 while (p) {
8087 if (p->id)
8088 free(p->id);
8089
8090 if (p->check_req)
8091 free(p->check_req);
8092
8093 if (p->cookie_name)
8094 free(p->cookie_name);
8095
8096 if (p->capture_name)
8097 free(p->capture_name);
8098
8099 /* only strup if the user have set in config.
8100 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008101 if (p->errmsg.msg400) free(p->errmsg.msg400);
8102 if (p->errmsg.msg403) free(p->errmsg.msg403);
8103 if (p->errmsg.msg408) free(p->errmsg.msg408);
8104 if (p->errmsg.msg500) free(p->errmsg.msg500);
8105 if (p->errmsg.msg502) free(p->errmsg.msg502);
8106 if (p->errmsg.msg503) free(p->errmsg.msg503);
8107 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008108 */
8109 if (p->appsession_name)
8110 free(p->appsession_name);
8111
8112 h = p->req_cap;
8113 while (h) {
8114 h_next = h->next;
8115 if (h->name)
8116 free(h->name);
8117 pool_destroy(h->pool);
8118 free(h);
8119 h = h_next;
8120 }/* end while(h) */
8121
8122 h = p->rsp_cap;
8123 while (h) {
8124 h_next = h->next;
8125 if (h->name)
8126 free(h->name);
8127
8128 pool_destroy(h->pool);
8129 free(h);
8130 h = h_next;
8131 }/* end while(h) */
8132
8133 s = p->srv;
8134 while (s) {
8135 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008136 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008137 free(s->id);
8138
willy tarreaub952e1d2005-12-18 01:31:20 +01008139 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008140 free(s->cookie);
8141
8142 free(s);
8143 s = s_next;
8144 }/* end while(s) */
8145
8146 l = p->listen;
8147 while (l) {
8148 l_next = l->next;
8149 free(l);
8150 l = l_next;
8151 }/* end while(l) */
8152
8153 pool_destroy((void **) p->req_cap_pool);
8154 pool_destroy((void **) p->rsp_cap_pool);
8155 p = p->next;
8156 }/* end while(p) */
8157
8158 if (global.chroot) free(global.chroot);
8159 if (global.pidfile) free(global.pidfile);
8160
willy tarreau12350152005-12-18 01:03:27 +01008161 if (StaticReadEvent) free(StaticReadEvent);
8162 if (StaticWriteEvent) free(StaticWriteEvent);
8163 if (fdtab) free(fdtab);
8164
8165 pool_destroy(pool_session);
8166 pool_destroy(pool_buffer);
8167 pool_destroy(pool_fdtab);
8168 pool_destroy(pool_requri);
8169 pool_destroy(pool_task);
8170 pool_destroy(pool_capture);
8171 pool_destroy(pool_appsess);
8172
8173 if (have_appsession) {
8174 pool_destroy(apools.serverid);
8175 pool_destroy(apools.sessid);
8176 }
8177} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008178
8179int main(int argc, char **argv) {
willy tarreaub1285d52005-12-18 01:20:14 +01008180 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008181 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008182 init(argc, argv);
8183
willy tarreau0f7af912005-12-17 12:21:26 +01008184 signal(SIGQUIT, dump);
8185 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008186 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008187#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008188 signal(SIGINT, sig_int);
8189 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008190#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008191
8192 /* on very high loads, a sigpipe sometimes happen just between the
8193 * getsockopt() which tells "it's OK to write", and the following write :-(
8194 */
willy tarreau3242e862005-12-17 12:27:53 +01008195#ifndef MSG_NOSIGNAL
8196 signal(SIGPIPE, SIG_IGN);
8197#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008198
willy tarreaud0fb4652005-12-18 01:32:04 +01008199 /* start_proxies() sends an alert when it fails. */
willy tarreau0f7af912005-12-17 12:21:26 +01008200 if (start_proxies() < 0)
8201 exit(1);
willy tarreaud0fb4652005-12-18 01:32:04 +01008202
8203 if (listeners == 0) {
8204 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
8205 exit(1);
8206 }
8207
willy tarreaudbd3bef2006-01-20 19:35:18 +01008208 /* prepare pause/play signals */
8209 signal(SIGTTOU, sig_pause);
8210 signal(SIGTTIN, sig_listen);
8211
Willy TARREAUe3283d12006-03-01 22:15:29 +01008212 if (global.mode & MODE_DAEMON) {
8213 global.mode &= ~MODE_VERBOSE;
8214 global.mode |= MODE_QUIET;
8215 }
8216
willy tarreaud0fb4652005-12-18 01:32:04 +01008217 /* MODE_QUIET can inhibit alerts and warnings below this line */
8218
8219 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008220 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008221 /* detach from the tty */
8222 fclose(stdin); fclose(stdout); fclose(stderr);
8223 close(0); close(1); close(2);
8224 }
willy tarreau0f7af912005-12-17 12:21:26 +01008225
willy tarreaufe2c5c12005-12-17 14:14:34 +01008226 /* open log & pid files before the chroot */
8227 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8228 int pidfd;
8229 unlink(global.pidfile);
8230 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8231 if (pidfd < 0) {
8232 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
8233 exit(1);
8234 }
8235 pidfile = fdopen(pidfd, "w");
8236 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008237
8238 /* chroot if needed */
8239 if (global.chroot != NULL) {
8240 if (chroot(global.chroot) == -1) {
8241 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
8242 exit(1);
8243 }
8244 chdir("/");
8245 }
8246
willy tarreaub1285d52005-12-18 01:20:14 +01008247 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01008248 if (!global.rlimit_nofile)
8249 global.rlimit_nofile = global.maxsock;
8250
willy tarreaub1285d52005-12-18 01:20:14 +01008251 if (global.rlimit_nofile) {
8252 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8253 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8254 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8255 }
8256 }
8257
willy tarreau9fe663a2005-12-17 13:02:59 +01008258 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008259 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008260 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8261 exit(1);
8262 }
8263
willy tarreau036e1ce2005-12-17 13:46:33 +01008264 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008265 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8266 exit(1);
8267 }
8268
willy tarreaub1285d52005-12-18 01:20:14 +01008269 /* check ulimits */
8270 limit.rlim_cur = limit.rlim_max = 0;
8271 getrlimit(RLIMIT_NOFILE, &limit);
8272 if (limit.rlim_cur < global.maxsock) {
8273 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",
8274 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8275 }
8276
willy tarreau9fe663a2005-12-17 13:02:59 +01008277 if (global.mode & MODE_DAEMON) {
8278 int ret = 0;
8279 int proc;
8280
8281 /* the father launches the required number of processes */
8282 for (proc = 0; proc < global.nbproc; proc++) {
8283 ret = fork();
8284 if (ret < 0) {
8285 Alert("[%s.main()] Cannot fork.\n", argv[0]);
8286 exit(1); /* there has been an error */
8287 }
8288 else if (ret == 0) /* child breaks here */
8289 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008290 if (pidfile != NULL) {
8291 fprintf(pidfile, "%d\n", ret);
8292 fflush(pidfile);
8293 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008294 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008295 /* close the pidfile both in children and father */
8296 if (pidfile != NULL)
8297 fclose(pidfile);
8298 free(global.pidfile);
8299
willy tarreau9fe663a2005-12-17 13:02:59 +01008300 if (proc == global.nbproc)
8301 exit(0); /* parent must leave */
8302
willy tarreau750a4722005-12-17 13:21:24 +01008303 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8304 * that we can detach from the TTY. We MUST NOT do it in other cases since
8305 * it would have already be done, and 0-2 would have been affected to listening
8306 * sockets
8307 */
8308 if (!(global.mode & MODE_QUIET)) {
8309 /* detach from the tty */
8310 fclose(stdin); fclose(stdout); fclose(stderr);
8311 close(0); close(1); close(2); /* close all fd's */
8312 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8313 }
willy tarreaua1598082005-12-17 13:08:06 +01008314 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008315 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008316 }
8317
willy tarreau1c2ad212005-12-18 01:11:29 +01008318#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008319 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008320 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8321 epoll_loop(POLL_LOOP_ACTION_RUN);
8322 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008323 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008324 }
8325 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008326 Warning("epoll() is not available. Using poll()/select() instead.\n");
8327 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008328 }
8329 }
8330#endif
8331
8332#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008333 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008334 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8335 poll_loop(POLL_LOOP_ACTION_RUN);
8336 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008337 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008338 }
8339 else {
8340 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008341 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008342 }
8343 }
8344#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008345 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008346 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8347 select_loop(POLL_LOOP_ACTION_RUN);
8348 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008349 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008350 }
8351 }
8352
willy tarreau0f7af912005-12-17 12:21:26 +01008353
willy tarreau12350152005-12-18 01:03:27 +01008354 /* Free all Hash Keys and all Hash elements */
8355 appsession_cleanup();
8356 /* Do some cleanup */
8357 deinit();
8358
willy tarreau0f7af912005-12-17 12:21:26 +01008359 exit(0);
8360}
willy tarreau12350152005-12-18 01:03:27 +01008361
8362#if defined(DEBUG_HASH)
8363static void print_table(const CHTbl *htbl) {
8364
8365 ListElmt *element;
8366 int i;
8367 appsess *asession;
8368
8369 /*****************************************************************************
8370 * *
8371 * Display the chained hash table. *
8372 * *
8373 *****************************************************************************/
8374
8375 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8376
8377 for (i = 0; i < TBLSIZ; i++) {
8378 fprintf(stdout, "Bucket[%03d]\n", i);
8379
8380 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8381 //fprintf(stdout, "%c", *(char *)list_data(element));
8382 asession = (appsess *)list_data(element);
8383 fprintf(stdout, "ELEM :%s:", asession->sessid);
8384 fprintf(stdout, " Server :%s: \n", asession->serverid);
8385 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8386 }
8387
8388 fprintf(stdout, "\n");
8389 }
8390 return;
8391} /* end print_table */
8392#endif
8393
8394static int appsession_init(void)
8395{
8396 static int initialized = 0;
8397 int idlen;
8398 struct server *s;
8399 struct proxy *p = proxy;
8400
8401 if (!initialized) {
8402 if (!appsession_task_init()) {
8403 apools.sessid = NULL;
8404 apools.serverid = NULL;
8405 apools.ser_waste = 0;
8406 apools.ser_use = 0;
8407 apools.ser_msize = sizeof(void *);
8408 apools.ses_waste = 0;
8409 apools.ses_use = 0;
8410 apools.ses_msize = sizeof(void *);
8411 while (p) {
8412 s = p->srv;
8413 if (apools.ses_msize < p->appsession_len)
8414 apools.ses_msize = p->appsession_len;
8415 while (s) {
8416 idlen = strlen(s->id);
8417 if (apools.ser_msize < idlen)
8418 apools.ser_msize = idlen;
8419 s = s->next;
8420 }
8421 p = p->next;
8422 }
8423 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8424 apools.ses_msize ++;
8425 }
8426 else {
8427 fprintf(stderr, "appsession_task_init failed\n");
8428 return -1;
8429 }
8430 initialized ++;
8431 }
8432 return 0;
8433}
8434
8435static int appsession_task_init(void)
8436{
8437 static int initialized = 0;
8438 struct task *t;
8439 if (!initialized) {
8440 if ((t = pool_alloc(task)) == NULL)
8441 return -1;
8442 t->next = t->prev = t->rqnext = NULL;
8443 t->wq = LIST_HEAD(wait_queue);
8444 t->state = TASK_IDLE;
8445 t->context = NULL;
8446 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8447 task_queue(t);
8448 t->process = appsession_refresh;
8449 initialized ++;
8450 }
8451 return 0;
8452}
8453
8454static int appsession_refresh(struct task *t) {
8455 struct proxy *p = proxy;
8456 CHTbl *htbl;
8457 ListElmt *element, *last;
8458 int i;
8459 appsess *asession;
8460 void *data;
8461
8462 while (p) {
8463 if (p->appsession_name != NULL) {
8464 htbl = &p->htbl_proxy;
8465 /* if we ever give up the use of TBLSIZ, we need to change this */
8466 for (i = 0; i < TBLSIZ; i++) {
8467 last = NULL;
8468 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8469 asession = (appsess *)list_data(element);
8470 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8471 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8472 int len;
8473 /*
8474 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8475 */
8476 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8477 asession->sessid, asession->serverid?asession->serverid:"(null)");
8478 write(1, trash, len);
8479 }
8480 /* delete the expired element from within the hash table */
8481 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8482 && (htbl->table[i].destroy != NULL)) {
8483 htbl->table[i].destroy(data);
8484 }
8485 if (last == NULL) {/* patient lost his head, get a new one */
8486 element = list_head(&htbl->table[i]);
8487 if (element == NULL) break; /* no heads left, go to next patient */
8488 }
8489 else
8490 element = last;
8491 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8492 else
8493 last = element;
8494 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8495 }
8496 }
8497 p = p->next;
8498 }
8499 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8500 return TBLCHKINT;
8501} /* end appsession_refresh */
8502